bytedance/deer-flow · error · OSError
Failed to save memory data after creating fact
Error message
Failed to save memory data after creating fact
What it means
create_memory_fact retries the whole read-check-write cycle 3 times when _save_memory_to_file loses a revision race. If every attempt fails (or the storage write fails for non-race reasons), it gives up with this OSError. The apply_changes backends handle conflicts internally, so this is the legacy/conditional-save path's exhaustion signal.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:992
raise AssertionError("bounded create retry did not return or raise")
# Legacy single-file path: same duplicate-rejection contract as the
# apply_changes path above. A revision-conflicted save (False) reloads
# the fresh snapshot and re-runs the duplicate check, so a concurrent
# creator's commit is rejected with ValueError("Duplicate fact")
# instead of surfacing as a generic save failure.
for attempt in range(3):
memory_data = self.get_memory_data(agent_name, user_id=user_id) if attempt == 0 else self.reload_memory_data(agent_name, user_id=user_id)
_raise_if_duplicate_fact_content(memory_data, candidate_key)
updated_memory = dict(memory_data)
updated_memory["facts"] = _trim_facts_to_max([*memory_data.get("facts", []), copy.deepcopy(candidate)], self._config.max_facts)
if self._save_memory_to_file(updated_memory, agent_name, user_id=user_id, expected_revision=int(memory_data.get("revision") or 0)):
# If the cap evicted the just-added (lower-confidence) fact,
# signal via None so callers don't report a dangling id as
# "added".
stored = any(f.get("id") == fact_id for f in updated_memory["facts"])
return updated_memory, (fact_id if stored else None)
logger.info("Retrying capped fact creation from a fresh snapshot after a revision conflict")
raise OSError("Failed to save memory data after creating fact")
def delete_memory_fact(self, fact_id: str, agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Delete a fact by its id 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"):
deleted = self._storage.get_fact(fact_id, agent_name=agent_name, user_id=user_id)
if deleted is None:
raise KeyError(fact_id)
global_memory = self.get_memory_data(user_id=user_id)
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(global_memory.get("revision") or 0),
allow_manifest_rebase=True,
)
return self.get_memory_data(agent_name, user_id=user_id)View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Reduce concurrency: serialize fact creation per agent (lock or queue) so revision races cannot repeat
- Retry the create call after a short backoff — a fresh snapshot usually succeeds once the concurrent writer finishes
- Verify the memory directory is writable and has disk space (persistent failure also exhausts retries)
- Use a storage backend implementing apply_changes, which resolves conflicts server-side
Defensive patterns
Strategy: retry
Try / catch
for attempt in range(3):
try:
_, fact_id = memory.create_memory_fact(content, agent_name=agent)
break
except OSError:
if attempt == 2:
raise
time.sleep(0.5 * (attempt + 1)) Prevention
- Serialize fact creation per agent (lock/queue) so revision races cannot repeat
- Use an apply_changes-capable storage backend when concurrent writers exist
When it happens
Trigger: Sustained concurrent writes to the same agent's memory file (e.g. two threads creating facts in a tight loop) that win the revision race 3 times in a row, or a persistent I/O failure (read-only file, full disk) making every save attempt fail.
Common situations: Parallel test suites hammering the same memory file, a background memory-update loop plus user-issued memory_add calls, or a broken storage mount that fails every write.
Related errors
- Failed to save memory data after deleting fact '{fact_id}'
- 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/01b2bec7a907282d.
Report an issue: GitHub.