Skip to content

NonEmptyGraphStoreError

Runtime.load(..., graph_store=store) or Runtime.fork(..., graph_store=store) was pointed at a GraphStore that already holds projection state. The call raises before applying any event and does not call clear(). A refused fork also writes no fork row and copies no events. operation is "load" or "fork".

Replay only upserts and removes entities the log names. Records already in the store would survive, so the rebuilt view could contain objects, relations, or patches that never happened. Clearing first is not safe either: if replay then fails, readers are left with an empty or partial projection.

Quick fix

Pass a store that is_empty() says is empty. A new in-memory store, or a FalkorDB graph name that has never been replayed into, qualifies:

from activegraph import InMemoryGraphStore, Runtime

store = InMemoryGraphStore()
rt = Runtime.load(path, run_id=run_id, graph_store=store)

Do not reuse a store that already holds this run or another run. Indexes created when a FalkorDB store opens are not projection state; leftover objects, relations, patches, and placeholder nodes are.

How to diagnose

The message names the store class and how many objects, relations, and patches it already held. Context carries the same numbers:

from activegraph import NonEmptyGraphStoreError, Runtime

try:
    rt = Runtime.load(path, run_id=run_id, graph_store=store)
except NonEmptyGraphStoreError as exc:
    print(exc.store_type)
    print(exc.objects, exc.relations, exc.patches)
    print(exc.run_id)

If all three counts are zero, the backend still reported hidden projection state (for example FalkorDB placeholder nodes that all_objects() does not list). That state would survive replay, so load refuses.

After the error, the GraphStore is unchanged and the event log has not gained events.

When does this fire

Any Runtime.load or Runtime.fork whose graph_store is not empty, including:

  • an in-memory store seeded by an earlier Graph(graph_store=store)
  • a FalkorDB graph that already holds another projection
  • the same store used for a second load after the first one filled it
  • a compacted run (snapshot plus suffix) replayed into a dirty store

The check is the same for every built-in GraphStore. Third-party stores answer through GraphStore.is_empty(). Objects are probed with query_objects(ObjectQuery(result_mode="exists")); relations and patches use all_relations and all_patches. A backend with state those reads cannot see must override is_empty and return False while that state would survive replay.

graph_store=None is a fresh in-memory store and does not raise.

Why the framework refuses to continue

The GraphStore is a disposable projection of one event log. A successful rebuild must not expose facts the log does not contain. Publishing that rebuild by clearing the live store and replaying in place is failure-prone, so this release refuses the dirty target instead. Building into an isolated store and swapping it in atomically is a later change.

See replay and using FalkorDB.