bytedance/deer-flow · error · MemoryStorageError

Failed to update global memory summaries

Error message

Failed to update global memory summaries

What it means

update_summaries() does load -> merge -> save(document, expected_revision) and raises MemoryStorageError when save() returns False. save() returns False on optimistic-concurrency failure (revision mismatch) or other non-exception commit rejections, meaning another writer changed the global memory document between the load and the save. Summaries are always user-global, never agent-specific, so the contention is on the user-level file.

Source

Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:1379

        agent_name: str | None = None,
    ) -> dict[str, Any]:
        document = self.load(agent_name, user_id=user_id)
        return {"user": copy.deepcopy(document.get("user", {})), "history": copy.deepcopy(document.get("history", {})), "revision": document.get("revision", 0)}

    def update_summaries(
        self,
        summaries: dict[str, Any],
        *,
        user_id: str | None = None,
        agent_name: str | None = None,
        expected_revision: int | None = None,
    ) -> dict[str, Any]:
        # Summaries are always user-global, never agent-specific.
        document = self.load(user_id=user_id)
        document.update({key: copy.deepcopy(value) for key, value in summaries.items() if key in {"user", "history"}})
        expected = int(document.get("revision") or 0) if expected_revision is None else expected_revision
        if not self.save(document, user_id=user_id, expected_revision=expected):
            raise MemoryStorageError("Failed to update global memory summaries")
        return self.reload(user_id=user_id)

    def notify_fact_upsert(self, fact: dict[str, Any], *, path: str = "") -> bool:
        if self._retrieval is None:
            return False
        scope = fact.get("scope") if isinstance(fact.get("scope"), dict) else {}
        self._retrieval.upsert(copy.deepcopy(fact), scope=copy.deepcopy(scope), path=path)
        return True

    def notify_fact_remove(self, fact_id: str, *, scope: dict[str, str | None]) -> bool:
        if self._retrieval is None:
            return False
        self._retrieval.remove(fact_id, scope=copy.deepcopy(scope))
        return True

    def search_facts(
        self,
        query: str,

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Retry the whole operation: catch MemoryStorageError, reload via storage.reload(user_id=...), re-apply the summary merge, save again (bounded attempts).
  2. Serialize summary updates per user_id with a lock in your service layer if retries are undesirable.
  3. Update summaries through a single owner (one coordinator) instead of many concurrent writers.

Example fix

# before
storage.update_summaries({"user": summary}, user_id=user_id)

# after
for attempt in range(3):
    try:
        storage.update_summaries({"user": summary}, user_id=user_id)
        break
    except MemoryStorageError:
        if attempt == 2:
            raise
        time.sleep(0.1 * (attempt + 1))
Defensive patterns

Strategy: retry

Try / catch

last_exc = None
for attempt in range(3):
    try:
        storage.update_summaries(summaries, user_id=user_id)
        break
    except MemoryStorageError as exc:
        last_exc = exc
        storage.reload(user_id=user_id)  # refresh revision before retry
else:
    raise last_exc

Prevention

When it happens

Trigger: Two threads/processes updating user summaries concurrently (e.g. two agents finishing turns for the same user at once); calling update_summaries repeatedly in a loop without reloading between attempts; passing an expected_revision that is already stale.

Common situations: Multi-agent workflows sharing one user_id; a memory updater racing with a fact save that also bumps the document revision; long-running processes holding an old revision across other writes.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/c657b1bce2b7bc08. Report an issue: GitHub.