FalkorDB driver: multi-group_id reads (get_episodes/search_nodes) silently query the wrong graph
Summary
With the FalkorDB driver, get_episodes/search_nodes (and other read paths that call EpisodicNode.get_by_group_ids / client.search_() directly) silently query the wrong graph and return empty results, depending on unrelated prior write activity on the same Graphiti client instance. This is a correctness bug, not a performance issue — reads can silently return no results even though the requested group_id has real data.
Environment
graphiti-core0.29.2 (installed viamcp_server's pinned deps)- Driver: FalkorDB
- Reproduced via the bundled MCP server (
mcp_server/src/graphiti_mcp_server.py), but the root cause is ingraphiti_coreitself, not the MCP server.
Root cause
FalkorDB is multi-tenant: each group_id lives in its own separate FalkorDB graph (confirmed via GRAPH.LIST — e.g. my-group-a, my-group-b show up as distinct top-level graphs, not as a group_id property inside one shared graph).
To route a write to the correct graph, add_episode mutates the shared driver in place:
# graphiti_core/graphiti.py (two call sites, e.g. ~line 1081 and ~1309)
self.driver = self.driver.clone(database=group_id)FalkorDriver.clone() returns a new driver instance bound to a different _database, but because it's assigned back onto self.driver, the shared Graphiti client's driver stays permanently rebound to whichever group_id was most recently written, until the next write changes it again.
Meanwhile, FalkorDriver.execute_query() always queries whatever self._database currently is — it does not accept or honor a per-call database/group override:
# graphiti_core/driver/falkordb_driver.py
async def execute_query(self, cypher_query_, **kwargs: Any):
graph = self._get_graph(self._database) # always the driver's *current* bound database
...And EpisodicNode.get_by_group_ids (graphiti_core/nodes.py) falls through to this same execute_query path, because FalkorDriver never sets graph_operations_interface (it's None by default on the base GraphDriver, confirmed by grepping the FalkorDB driver module — no override exists):
async def get_by_group_ids(cls, driver, group_ids, limit=None, uuid_cursor=None):
if driver.graph_operations_interface: # always None for FalkorDriver
...
records, _, _ = await driver.execute_query(
"MATCH (e:Episodic) WHERE e.group_id IN $group_ids ...",
group_ids=group_ids, ...
)So group_ids is only ever used as a Cypher WHERE-clause filter value, never to select which graph to run the query against. The query runs against whatever the shared driver's _database currently happens to be — which is a leftover side effect of the last add_episode (or similar) call on that client, completely unrelated to the group_ids the caller actually asked for. client.search_() (used by search_nodes) has the same issue, since it also goes through the shared self.driver.
Reproduction
- Start an MCP server (or any long-lived
Graphiticlient) against FalkorDB. add_episode(..., group_id="a")— this rebinds the shared driver to graph"a".add_episode(..., group_id="b")— rebinds the shared driver to graph"b".- Call
get_episodes(group_ids=["a"])(orsearch_nodes(group_ids=["a"], ...)). - Expected: episodes from group
"a"are returned. - Actual: empty result — the query ran against graph
"b"(the driver's current binding) filtered bygroup_id == "a", which matches nothing, because group"b"'s graph has no nodes withgroup_id == "a".
This can be confirmed independently of the MCP server by querying FalkorDB directly (GRAPH.QUERY <group_id> "MATCH (n) RETURN count(n)") and seeing real data exists in the graph that the MCP tool just reported as empty.
Impact
Any application juggling multiple group_ids against a single long-lived Graphiti client + FalkorDB driver — which the bundled MCP server explicitly supports and encourages — will see reads intermittently and silently return empty results for perfectly valid group_ids, with no error raised. This is easy to mistake for "no data" or general flakiness rather than a routing bug, since nothing indicates the query ran against the wrong graph.
Suggested fix
Either:
- Make
FalkorDriver.execute_query(and thesession()/wherever else_databaseis read) accept a per-calldatabase/group_idoverride instead of relying on a mutable sharedself._database, and haveget_by_group_ids/search_pass it explicitly per group_id (looping + merging across group_ids, similar to whatadd_episode's per-group cloning already implies is necessary); or - Stop mutating
self.driverin place inadd_episode, and instead pass a per-call cloned driver down through the write path without touching the shared client state, so the shared driver's_databasestays stable at whatever it was constructed with.
Happy to provide more detail or test a patch against a local FalkorDB instance if useful.
Source: getzep/graphiti