bytedance/deer-flow · error · OSError

Failed to save memory data after updating fact '{fact_id}'

Error message

Failed to save memory data after updating fact '{fact_id}'

What it means

The final legacy-path persistence step of update_memory_fact: after building updated_facts and confirming the target exists, _save_memory_to_file returns False and the update is discarded with this OSError. As with other legacy saves, False means a lost revision race or an I/O failure.

Source

Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:1092

                    updated_fact["confidence"] = _validate_confidence(confidence)
                updated_facts.append(updated_fact)
            else:
                updated_facts.append(fact)
        if not found:
            raise KeyError(fact_id)
        if getattr(type(self._storage), "apply_changes", None) is not MemoryStorage.apply_changes:
            changed = next(fact for fact in updated_facts if fact.get("id") == fact_id)
            self._storage.apply_changes(
                {"upserts": [changed], "upsertRevisions": {fact_id: int(changed.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["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 updating fact '{fact_id}'")
        return updated_memory

    def _build_signal_hints(self, signals: frozenset[str]) -> str:
        """Build optional prompt hints for the detected signal classes.

        Each present signal contributes one instruction nudging the extraction
        LLM toward the right category and confidence. The variable is still
        rendered into the template's ``{correction_hint}`` slot (the name is
        historical -- it now carries the full signal-hint set, plus the manual
        fact note appended by :meth:`_prepare_update_prompt`).
        """
        hints: list[str] = []
        if "correction" in signals:
            hints.append(
                "IMPORTANT: Explicit correction signals were detected in this conversation. "
                "Record a correction with confidence >= 0.95 only when it describes a durable, user-level "
                "working preference that is safe to reuse across unrelated tasks. A correction to facts, files, "
                "directions, or constraints in the current task is thread- or project-scoped and must not be stored."

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Retry the update after the concurrent write settles
  2. Serialize memory mutations per agent to avoid revision races entirely
  3. Verify storage writability and space if the error repeats deterministically
Defensive patterns

Strategy: retry

Try / catch

try:
    memory.update_memory_fact(fact_id, content=content, agent_name=agent)
except OSError:
    time.sleep(0.2)
    memory.update_memory_fact(fact_id, content=content, agent_name=agent)

Prevention

When it happens

Trigger: Concurrent memory writes (background updater vs. user edit) winning the revision race, or the memory file being unwritable/full at save time.

Common situations: Fact edits racing scheduled memory-update jobs; degraded storage volumes.

Related errors


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