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_memoryView on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-read the fact's current revision and retry the delete with the correct expected revision.
- 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.