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

  1. Retry the delete — it re-reads the fresh snapshot and is idempotent (a KeyError on retry means it actually succeeded)
  2. Eliminate the concurrent writer or serialize memory mutations per agent
  3. 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

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


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