bytedance/deer-flow · error · MemoryFactRevisionConflict

Expected fact {fact_id!r} revision {delete_revisions[fact_id

Error message

Expected fact {fact_id!r} revision {delete_revisions[fact_id]}, found {existing.get('revision')}

What it means

Error "Expected fact {fact_id!r} revision {delete_revisions[fact_id]}, found {existing.get('revision')}" thrown in bytedance/deer-flow.

Source

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

                        raise MemoryFactRevisionConflict(f"Expected fact {fact_id!r} revision {expected_fact_revision}, found {actual_fact_revision}")
            normalized = _normalize_fact(candidate, scope=scope, existing=existing)
            if existing != normalized:
                prepared[fact_id] = (normalized, existing, fact_path)

        delete_ids = [str(fact_id) for fact_id in deletes]
        if len(delete_ids) != len(set(delete_ids)):
            raise ValueError("Duplicate fact ids are not allowed in deletes")
        removals: dict[str, tuple[dict[str, Any], Path]] = {}
        for fact_id in delete_ids:
            if fact_id in prepared:
                raise ValueError(f"Fact {fact_id!r} cannot be upserted and deleted together")
            if agent_name is None:  # guarded above
                raise ValueError("agent_name is required for fact repository changes")
            existing, fact_path = self._read_fact(path, fact_id, user_id=user_id, agent_name=agent_name)
            if existing is None:
                continue
            if delete_revisions and fact_id in delete_revisions and delete_revisions[fact_id] != existing.get("revision"):
                raise MemoryFactRevisionConflict(f"Expected fact {fact_id!r} revision {delete_revisions[fact_id]}, found {existing.get('revision')}")
            removals[fact_id] = (existing, fact_path)

        base = current_memory or create_empty_memory()
        user_section = copy.deepcopy(base.get("user", {}))
        history_section = copy.deepcopy(base.get("history", {}))
        if summaries is not None:
            if not isinstance(summaries, dict):
                raise ValueError("change_set.summaries must be an object")
            if "user" in summaries:
                if not isinstance(summaries["user"], dict):
                    raise ValueError("change_set.summaries.user must be an object")
                user_section.update(copy.deepcopy(summaries["user"]))
            if "history" in summaries:
                if not isinstance(summaries["history"], dict):
                    raise ValueError("change_set.summaries.history must be an object")
                history_section.update(copy.deepcopy(summaries["history"]))
        summaries_changed = user_section != base.get("user", {}) or history_section != base.get("history", {})
        needs_manifest_cleanup = current_memory is None or current_memory.get("version") != DOCUMENT_VERSION or "facts" in current_memory

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Re-read the fact's current revision and retry the delete with the correct expected revision.
  2. Another writer modified the fact concurrently; coordinate writers.

When it happens

Trigger: Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:770 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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