Skip to content

Commit 74e1188

Browse files
committed
fix: use NEO4J_DATABASE env var instead of config dict for non-default database
mem0ai's graph_memory.py passes config as positional args to Neo4jGraph() where pos 3 is `token`, not `database`. Setting database in the config dict causes it to land in the token parameter, resulting in AuthenticationError. Use NEO4J_DATABASE env var which langchain_neo4j reads via get_from_dict_or_env(). Upstream: mem0ai #3906, #3981, #4085 (none merged) Resolves: PAR-57
1 parent b5bc6ab commit 74e1188

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

src/mem0_mcp_selfhosted/config.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from __future__ import annotations
88

9+
import os
910
from typing import Any, TypedDict
1011

1112
from mem0_mcp_selfhosted.auth import resolve_token
@@ -153,7 +154,15 @@ def build_config() -> tuple[dict[str, Any], list[ProviderInfo], dict[str, Any] |
153154
"password": neo4j_password,
154155
}
155156
if neo4j_database:
156-
graph_neo4j_config["database"] = neo4j_database
157+
# WORKAROUND: mem0ai's graph_memory.py passes config values as
158+
# positional args to Neo4jGraph(url, username, password, ...) where
159+
# the 4th param is `token`, NOT `database`. Putting database in the
160+
# config dict causes it to land in token → AuthError.
161+
# Set NEO4J_DATABASE env var instead — langchain_neo4j reads it via
162+
# get_from_dict_or_env(). Upstream: mem0ai #3906, #3981, #4085.
163+
# NOTE: Intentional process-global mutation — Neo4jGraph reads this
164+
# env var at init time, which happens after build_config() returns.
165+
os.environ["NEO4J_DATABASE"] = neo4j_database
157166
if neo4j_base_label:
158167
graph_neo4j_config["base_label"] = neo4j_base_label
159168

tests/unit/test_config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,42 @@ def test_graph_disabled(self):
6767
config_dict, *_ = self._build_with_env(env)
6868
assert "graph_store" not in config_dict
6969

70+
def test_neo4j_database_uses_env_var(self):
71+
"""MEM0_NEO4J_DATABASE sets NEO4J_DATABASE env var, not config dict.
72+
73+
mem0ai's graph_memory.py passes config as positional args to
74+
Neo4jGraph(url, username, password, ...) where pos 3 is `token`,
75+
not `database`. Putting database in the config dict causes AuthError.
76+
"""
77+
test_env = {"MEM0_ENABLE_GRAPH": "true", "MEM0_NEO4J_DATABASE": "mydb"}
78+
leak_keys = [k for k in os.environ if k.startswith("MEM0_")]
79+
with patch.dict("os.environ", test_env, clear=False) as patched_env:
80+
for k in leak_keys:
81+
if k not in test_env:
82+
patched_env.pop(k, None)
83+
with patch("mem0_mcp_selfhosted.config.resolve_token", return_value="sk-test"):
84+
from mem0_mcp_selfhosted.config import build_config
85+
config_dict, *_ = build_config()
86+
87+
# database must NOT be in the config dict (would land in token param)
88+
assert "database" not in config_dict["graph_store"]["config"]
89+
# instead, NEO4J_DATABASE env var must be set for langchain_neo4j
90+
assert os.environ.get("NEO4J_DATABASE") == "mydb"
91+
92+
def test_neo4j_database_not_set_when_absent(self):
93+
"""NEO4J_DATABASE env var not set when MEM0_NEO4J_DATABASE is absent."""
94+
test_env = {"MEM0_ENABLE_GRAPH": "true"}
95+
leak_keys = [k for k in os.environ if k.startswith("MEM0_")]
96+
with patch.dict("os.environ", test_env, clear=False) as patched_env:
97+
for k in leak_keys:
98+
if k not in test_env:
99+
patched_env.pop(k, None)
100+
patched_env.pop("NEO4J_DATABASE", None)
101+
with patch("mem0_mcp_selfhosted.config.resolve_token", return_value="sk-test"):
102+
from mem0_mcp_selfhosted.config import build_config
103+
build_config()
104+
assert "NEO4J_DATABASE" not in os.environ
105+
70106
def test_explicit_embedder_provider(self):
71107
"""Embedder provider is always explicit (never default to openai)."""
72108
config_dict, *_ = self._build_with_env({})

0 commit comments

Comments
 (0)