666ghj/MiroFish · error · RuntimeError
Zep updater for {simulation_id} is still active
Error message
Zep updater for {simulation_id} is still active What it means
Raised by ZepGraphMemoryUpdater.discard_inactive_updater when graph destruction tries to remove an updater from the class-level registry but the updater still has _running set or its worker thread is alive. The guard exists so explicit graph deletion never discards an updater that is still writing to the graph being destroyed.
Source
Thrown at backend/app/services/zep_graph_memory_updater.py:717
def get_simulation_ids(cls) -> List[str]:
"""Return every simulation with a retained updater."""
with cls._lock:
return sorted(cls._updaters)
@classmethod
def discard_inactive_updater(cls, simulation_id: str) -> bool:
"""Discard a failed, fully stopped updater during graph destruction."""
with cls._lock:
updater = cls._updaters.get(simulation_id)
if updater is None:
return False
worker_alive = bool(
updater._worker_thread and updater._worker_thread.is_alive()
)
if updater._running or worker_alive:
raise RuntimeError(
f"Zep updater for {simulation_id} is still active"
)
cls._updaters.pop(simulation_id, None)
logger.warning(
"Discarded incomplete Zep updater during explicit graph deletion: "
"simulation_id=%s, graph_id=%s",
simulation_id,
updater.graph_id,
)
return True
@classmethod
def stop_updater(cls, simulation_id: str):
"""停止并移除模拟的更新器"""
with cls._lock:
updater = cls._updaters.get(simulation_id)
if updater is None:
returnView on GitHub (pinned to b5b53acc57)
Solutions
- Call stop() (with a drain deadline) and wait for the worker thread to join before discard_inactive_updater
- If stop() previously failed, inspect updater state (get_stats / logs) and retry stop with a longer budget
- Only after the updater is fully quiescent call discard_inactive_updater again
- Never force-pop the registry entry while the thread is alive — the thread would keep writing to a deleted graph
Example fix
# before
updater.stop()
ZepGraphMemoryUpdater.discard_inactive_updater(sim_id) # thread may still be alive
# after
updater.stop()
updater._worker_thread.join(timeout=30)
if updater._worker_thread.is_alive():
raise RuntimeError("worker thread did not exit; refusing to delete graph")
ZepGraphMemoryUpdater.discard_inactive_updater(sim_id) Defensive patterns
Strategy: validation
Validate before calling
updater = ZepGraphMemoryUpdater._updaters.get(sim_id)
if updater and (updater._running or (updater._worker_thread and updater._worker_thread.is_alive())):
raise RuntimeError(f"cannot delete graph: updater for {sim_id} still active")
ZepGraphMemoryUpdater.discard_inactive_updater(sim_id) Try / catch
try:
ZepGraphMemoryUpdater.discard_inactive_updater(sim_id)
except RuntimeError:
# stop properly first, then retry discard
updater.stop(); updater._worker_thread.join(timeout=30)
ZepGraphMemoryUpdater.discard_inactive_updater(sim_id) Prevention
- Always stop() and join the worker thread before graph deletion
- Treat a failed stop() as blocking: do not proceed to deletion until resolved
- Never bypass the registry guard; a live thread writing to a deleted graph corrupts state
When it happens
Trigger: Calling discard_inactive_updater(simulation_id) after stop() failed or before the worker thread fully exited (stop initiated but thread.join not completed, or stop raised and left _running true). The class lock is held while raising, so the updater stays registered.
Common situations: Error-path cleanup: a previous stop() raised (e.g. Zep API error during final flush) leaving the updater half-stopped, then the user deletes the graph; or a race where deletion is requested moments after stop while the worker is mid-batch.
Related errors
- Graph {graph_id} is in use by active consumer(s): {', '.join
- 部分图谱更新器未完整停止: {details}
- production node pagination did not match raw cursor traversa
- production edge pagination did not match raw cursor traversa
- Persisted Zep batch does not match the current graph input
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/2b7e7243adb4ce7a.
Report an issue: GitHub.