bytedance/deer-flow · error · ValueError
Duplicate fact ids are not allowed in deletes
Error message
Duplicate fact ids are not allowed in deletes
What it means
Error "Duplicate fact ids are not allowed in deletes" thrown in bytedance/deer-flow.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:759
raise ValueError(f"Duplicate fact id {fact_id!r} in upserts")
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 upsert_revisions is not None and fact_id in upsert_revisions:
expected_fact_revision = upsert_revisions[fact_id]
if expected_fact_revision is None and existing is not None:
raise MemoryFactRevisionConflict(f"Fact {fact_id!r} must not already exist")
if expected_fact_revision is not None:
actual_fact_revision = None if existing is None else existing.get("revision")
if actual_fact_revision != expected_fact_revision:
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):View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Deduplicate the deletes list; each fact id may appear once.
- Fix the client building the change set to unique the ids.
When it happens
Trigger: Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:759 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/8dd6b5a5db99f599.
Report an issue: GitHub.