#1842·graphiti

FalkorDB driver: multi-group_id reads (get_episodes/search_nodes) silently query the wrong graph

Author: jdbwayCreated Sep 7, 2026Updated Sep 12, 2026

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-core 0.29.2 (installed via mcp_server's pinned deps)
  • Driver: FalkorDB
  • Reproduced via the bundled MCP server (mcp_server/src/graphiti_mcp_server.py), but the root cause is in graphiti_core itself, 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:

python
# 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:

python
# 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):

python
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

  1. Start an MCP server (or any long-lived Graphiti client) against FalkorDB.
  2. add_episode(..., group_id="a") — this rebinds the shared driver to graph "a".
  3. add_episode(..., group_id="b") — rebinds the shared driver to graph "b".
  4. Call get_episodes(group_ids=["a"]) (or search_nodes(group_ids=["a"], ...)).
  5. Expected: episodes from group "a" are returned.
  6. Actual: empty result — the query ran against graph "b" (the driver's current binding) filtered by group_id == "a", which matches nothing, because group "b"'s graph has no nodes with group_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 the session()/wherever else _database is read) accept a per-call database/group_id override instead of relying on a mutable shared self._database, and have get_by_group_ids/search_ pass it explicitly per group_id (looping + merging across group_ids, similar to what add_episode's per-group cloning already implies is necessary); or
  • Stop mutating self.driver in place in add_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 _database stays stable at whatever it was constructed with.

Happy to provide more detail or test a patch against a local FalkorDB instance if useful.