{"record":{"id":"170e2029e9f12892","repo":"bytedance/deer-flow","slug":"failed-to-save-memory-data-after-updating-fact-f","errorCode":null,"errorMessage":"Failed to save memory data after updating fact '{fact_id}'","messagePattern":"Failed to save memory data after updating fact '(.+?)'","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py","lineNumber":1092,"sourceCode":"                    updated_fact[\"confidence\"] = _validate_confidence(confidence)\n                updated_facts.append(updated_fact)\n            else:\n                updated_facts.append(fact)\n        if not found:\n            raise KeyError(fact_id)\n        if getattr(type(self._storage), \"apply_changes\", None) is not MemoryStorage.apply_changes:\n            changed = next(fact for fact in updated_facts if fact.get(\"id\") == fact_id)\n            self._storage.apply_changes(\n                {\"upserts\": [changed], \"upsertRevisions\": {fact_id: int(changed.get(\"revision\") or 1)}},\n                agent_name=agent_name,\n                user_id=user_id,\n                expected_manifest_revision=int(memory_data.get(\"revision\") or 0),\n                allow_manifest_rebase=True,\n            )\n            return self.get_memory_data(agent_name, user_id=user_id)\n        updated_memory[\"facts\"] = updated_facts\n        if not self._save_memory_to_file(updated_memory, agent_name, user_id=user_id, expected_revision=int(memory_data.get(\"revision\") or 0)):\n            raise OSError(f\"Failed to save memory data after updating fact '{fact_id}'\")\n        return updated_memory\n\n    def _build_signal_hints(self, signals: frozenset[str]) -> str:\n        \"\"\"Build optional prompt hints for the detected signal classes.\n\n        Each present signal contributes one instruction nudging the extraction\n        LLM toward the right category and confidence. The variable is still\n        rendered into the template's ``{correction_hint}`` slot (the name is\n        historical -- it now carries the full signal-hint set, plus the manual\n        fact note appended by :meth:`_prepare_update_prompt`).\n        \"\"\"\n        hints: list[str] = []\n        if \"correction\" in signals:\n            hints.append(\n                \"IMPORTANT: Explicit correction signals were detected in this conversation. \"\n                \"Record a correction with confidence >= 0.95 only when it describes a durable, user-level \"\n                \"working preference that is safe to reuse across unrelated tasks. A correction to facts, files, \"\n                \"directions, or constraints in the current task is thread- or project-scoped and must not be stored.\"","sourceCodeStart":1074,"sourceCodeEnd":1110,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py#L1074-L1110","documentation":"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.","triggerScenarios":"Concurrent memory writes (background updater vs. user edit) winning the revision race, or the memory file being unwritable/full at save time.","commonSituations":"Fact edits racing scheduled memory-update jobs; degraded storage volumes.","solutions":["Retry the update after the concurrent write settles","Serialize memory mutations per agent to avoid revision races entirely","Verify storage writability and space if the error repeats deterministically"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    memory.update_memory_fact(fact_id, content=content, agent_name=agent)\nexcept OSError:\n    time.sleep(0.2)\n    memory.update_memory_fact(fact_id, content=content, agent_name=agent)","preventionTips":["Avoid overlapping user edits with background memory-update writes","Track storage health; persistent OSError after retries means I/O, not a race"],"tags":["memory","deermem","persistence","concurrency","update"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}