#1876·graphiti

[BUG] group_id selects a database for writes but not for reads: add_episode persists to the cloned database, search/get_episodes query the configured one

Author: brentkearneyCreated Sep 10, 2026Updated Sep 11, 2026

Problem

add_episode resolves a per-group database, but read paths do not. Writes and reads therefore target different databases whenever group_id differs from the driver's configured database, and reads come back empty with no error.

_resolve_request_scope (added in #1699 to fix #1676) clones the driver per call:

python
if group_id == self.driver._database:
    return group_id, self.driver, self.clients

driver = self.driver.clone(database=group_id)
clients = self.clients.model_copy(update={'driver': driver})
return group_id, driver, clients

Only add_episode and add_episode_bulk call it. The read paths do not:

  • Graphiti.search() passes self.clients and an optional caller-supplied driver; it never derives one from group_ids.
  • The MCP server's get_episodes calls EpisodicNode.get_by_group_ids(client.driver, ...) on the base driver.

So an episode written under group_id="X" lands in database X, while a read for group_ids=["X"] runs against the configured database and finds nothing.

Reproduction

Using the MCP server against FalkorDB with a deliberate mismatch:

  • FALKORDB_DATABASE=smoke_db
  • GRAPHITI_GROUP_ID=smoke_0302

Steps:

  1. add_memory three episodes. Each reports success, and the server logs Successfully processed episode ... for group smoke_0302.
  2. GRAPH.LIST shows two graphs, smoke_db and smoke_0302. All three Episodic nodes are in smoke_0302, confirming the write clone worked.
  3. get_episodes returns No episodes found for group_ids="smoke_0302", for ["smoke_0302"], and for the default.

Expected: the episodes just written are returned. Actual: nothing, with no error.

Why this is easy to miss

The single-database deployment is unaffected: when group_id equals the configured database, _resolve_request_scope returns the shared driver unchanged, so writes and reads agree. The failure needs group_id != database, which is exactly the multi-tenant shape #1676 was about.

It also fails silently. Ingestion reports success, the data is genuinely persisted, and the read returns an empty result rather than an error — so it presents as "memory not working" rather than as a misconfiguration.

Suggested fix

Resolve the request scope on read paths too, so a group_id selects the same database for reads as for writes. Two shapes seem plausible:

  1. Have search() / search_() and the episode accessors derive the driver from group_ids the way add_episode does, when a single group_id is given.
  2. Or reject the mismatch at construction time, if targeting a database other than the one a group_id maps to is meant to be unsupported.

The choice depends on whether group_id is intended to name the database or merely to partition within it. Right now the write path treats it as the former and the read path as the latter, and that disagreement is the bug.

Related

  • #1676 — concurrent multi-group_id isolation, the original report
  • #1699 — the fix, which covered the write path