bytedance/deer-flow · error · OSError
Failed to save memory data after deleting fact '{fact_id}'
Error message
Failed to save memory data after deleting fact '{fact_id}' What it means
After a successful legacy-path delete, the updated fact list is persisted via _save_memory_to_file with the snapshot's revision; if that save returns False this OSError is raised. The delete itself was computed but not durably stored — the in-memory copy and the file now disagree.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:1029
memory_data = self.get_memory_data(agent_name, user_id=user_id)
facts = memory_data.get("facts", [])
updated_facts = [fact for fact in facts if fact.get("id") != fact_id]
if len(updated_facts) == len(facts):
raise KeyError(fact_id)
deleted = next(fact for fact in facts if fact.get("id") == fact_id)
if getattr(type(self._storage), "apply_changes", None) is not MemoryStorage.apply_changes:
self._storage.apply_changes(
{"deletes": [fact_id], "deleteRevisions": {fact_id: int(deleted.get("revision") or 1)}},
agent_name=agent_name,
user_id=user_id,
expected_manifest_revision=int(memory_data.get("revision") or 0),
allow_manifest_rebase=True,
)
return self.get_memory_data(agent_name, user_id=user_id)
updated_memory = dict(memory_data)
updated_memory["facts"] = updated_facts
if not self._save_memory_to_file(updated_memory, agent_name, user_id=user_id, expected_revision=int(memory_data.get("revision") or 0)):
raise OSError(f"Failed to save memory data after deleting fact '{fact_id}'")
return updated_memory
def update_memory_fact(self, fact_id: str, content: str | None = None, category: str | None = None, confidence: float | None = None, agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Update an existing fact and persist the updated memory data."""
if agent_name is None:
raise ValueError("agent_name")
if getattr(type(self._storage), "apply_changes", None) is not MemoryStorage.apply_changes and hasattr(self._storage, "get_fact"):
updated_fact = self._storage.get_fact(fact_id, agent_name=agent_name, user_id=user_id)
if updated_fact is None:
raise KeyError(fact_id)
if content is not None:
normalized_content = content.strip()
if not normalized_content:
raise ValueError("content")
updated_fact["content"] = normalized_content
if category is not None:
updated_fact["category"] = category.strip() or "context"
if confidence is not None:View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Retry the delete — it re-reads the fresh snapshot and is idempotent (a KeyError on retry means it actually succeeded)
- Eliminate the concurrent writer or serialize memory mutations per agent
- Check writability and disk space on the memory storage path
Defensive patterns
Strategy: retry
Try / catch
try:
memory.delete_memory_fact(fact_id, agent_name=agent)
except OSError:
time.sleep(0.2)
try:
memory.delete_memory_fact(fact_id, agent_name=agent)
except KeyError:
pass # first attempt actually committed the delete Prevention
- Serialize memory mutations per agent to avoid revision races
- Alert on repeated OSError from memory saves — it signals storage degradation
When it happens
Trigger: Legacy file storage where the conditional write fails: concurrent writer bumped the revision between read and save, or the memory file/directory became unwritable between the read and the write.
Common situations: Deleting a fact while a background memory-update LLM call is writing, permission changes on the data dir, or disk-full conditions.
Related errors
- Failed to save memory data after creating fact
- Failed to save memory data after updating fact '{fact_id}'
- Failed to update global memory summaries
- Failed to save imported memory data
- Failed to save cleared memory data
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/2804ae4486d106ca.
Report an issue: GitHub.