666ghj/MiroFish · error · RuntimeError

部分图谱更新器未完整停止: {details}

Error message

部分图谱更新器未完整停止: {details}

What it means

Raised by the class-level stop_all(): it attempts to stop every registered updater, collects (simulation_id, error) pairs for failures, and if any stop failed, raises RuntimeError with a joined per-simulation detail string. It is an aggregate error — some updaters may have stopped successfully while others did not; _stop_all_done is set only when the registry is empty.

Source

Thrown at backend/app/services/zep_graph_memory_updater.py:782

            except Exception as error:
                # Keep a failed updater registered so the caller can retry and
                # lifecycle/report guards still see the incomplete ingestion.
                logger.error(
                    "停止更新器失败: simulation_id=%s, error=%s",
                    simulation_id,
                    error,
                )
                errors.append((simulation_id, error))

        with cls._lock:
            cls._stop_all_done = not cls._updaters

        if errors:
            details = "; ".join(
                f"{simulation_id}: {error}"
                for simulation_id, error in errors
            )
            raise RuntimeError(f"部分图谱更新器未完整停止: {details}")
        logger.info("已停止所有图谱记忆更新器")
    
    @classmethod
    def get_all_stats(cls) -> Dict[str, Dict[str, Any]]:
        """获取所有更新器的统计信息"""
        return {
            sim_id: updater.get_stats() 
            for sim_id, updater in cls._updaters.items()
        }

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Parse the per-simulation details in the message to identify exactly which updaters failed and why (the inner error text is included)
  2. Retry stop_all (or stop the specific simulations) with a longer deadline — successful updaters are already gone, only failures remain
  3. If Zep was unreachable, restore connectivity first, then retry
  4. For shutdown code paths, decide explicitly whether to abandon unflushed activities (force stop without drain) rather than failing process exit

Example fix

# before
try:
    ZepGraphMemoryUpdater.stop_all()
except RuntimeError as e:
    os._exit(1)

# after
try:
    ZepGraphMemoryUpdater.stop_all()
except RuntimeError as e:
    logger.error("shutdown incomplete: %s", e)
    ZepGraphMemoryUpdater.stop_all()  # retried; only failed updaters remain
Defensive patterns

Strategy: retry

Try / catch

try:
    ZepGraphMemoryUpdater.stop_all()
except RuntimeError as e:
    logger.error("partial stop failure: %s", e)
    # already-stopped updaters are gone; retry only the failures
    ZepGraphMemoryUpdater.stop_all()

Prevention

When it happens

Trigger: Application shutdown while one or more updaters raise during stop(): common causes are the drain/ingestion TimeoutErrors (errors 61-63), Zep API failures during final flush, or worker threads refusing to join. Each failed stop is recorded and re-raised together.

Common situations: Process exit during active simulations, Zep Cloud unreachable at shutdown, or large buffered backlogs that cannot drain within the shutdown deadline.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/96840a6d946ab8df. Report an issue: GitHub.