{"record":{"id":"a62c2b0f178470f3","repo":"bytedance/deer-flow","slug":"update-fact-not-supported-by-type-self-name","errorCode":null,"errorMessage":"update_fact not supported by {type(self).__name__}","messagePattern":"update_fact not supported by (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"backend/packages/harness/deerflow/agents/memory/manager.py","lineNumber":431,"sourceCode":"        *,\n        agent_name: str | None = None,\n        user_id: str | None = None,\n    ) -> dict[str, Any]:\n        \"\"\"Delete one fact by id. Default: unsupported.\"\"\"\n        raise NotImplementedError(f\"delete_fact not supported by {type(self).__name__}\")\n\n    def update_fact(\n        self,\n        fact_id: str,\n        content: str | None = None,\n        category: str | None = None,\n        confidence: float | None = None,\n        *,\n        agent_name: str | None = None,\n        user_id: str | None = None,\n    ) -> dict[str, Any]:\n        \"\"\"Update one fact by id (preserving omitted fields). Default: unsupported.\"\"\"\n        raise NotImplementedError(f\"update_fact not supported by {type(self).__name__}\")\n\n    # B-class: no agent-side caller yet -- signatures only, for future scenarios.\n    # Default no-op so callers can invoke unconditionally without gating. (The\n    # self-serving hooks on_delegation / on_session_end / on_memory_write are\n    # deliberately NOT contracted: no caller, no event source, or subsumed by\n    # the callbacks field.)\n    def on_pre_compress(self, messages: list[Any]) -> str:\n        \"\"\"Memory -> compressor feedback (future memory-driven summary\n        enrichment). Returns text to inject into the compression prompt\n        (default: none).\"\"\"\n        return \"\"\n\n    def on_turn_start(self, turn_number: int, message: Any, **kwargs: Any) -> None:\n        \"\"\"Turn-start nudge (future background review). Default: no-op.\"\"\"\n        return None\n\n    # ── Async (speculative) ──────────────────────────────────────────────\n    # Interface placeholders so a future async LLM client can override without","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/manager.py#L413-L449","documentation":"MemoryManager.update_fact raises NotImplementedError as the optional per-fact CRUD default for partial fact updates (content/category/confidence with omitted fields preserved). Like create_fact/delete_fact, it is a DeerMem capability: backends without locally-addressable fact records (noop, mem0, honcho, openviking) inherit the raising default. The error indicates the selected memory backend does not support editing individual facts.","triggerScenarios":"Calling MemoryManager.update_fact(fact_id, content=..., confidence=..., agent_name=..., user_id=...) — via the memory_update tool in memory.mode: tool, a fact-editing UI action, or a script — while memory.manager_class resolves to a backend that does not override update_fact.","commonSituations":"Editing a fact in a settings UI after the deployment switched to a remote memory backend; memory.mode: tool runs against mem0/honcho; scripted fact corrections (e.g. updating confidence thresholds) written for the default file backend.","solutions":["Run the deermem backend (memory.manager_class: deermem) when per-fact editing is a requirement.","Emulate the update on capable-remote backends as delete+recreate through the backend's supported paths, or let middleware-mode extraction correct facts conversationally.","Custom backend authors: override update_fact on the MemoryManager subclass, preserving omitted-field semantics.","Capability-check before exposing edit actions in tooling."],"exampleFix":"# before\nmemory = manager.update_fact(fact_id, confidence=0.9, user_id=\"u1\")\n\n# after\nif type(manager).update_fact is MemoryManager.update_fact:\n    raise UnsupportedOperation(\"fact updates unsupported by this backend\")\nmemory = manager.update_fact(fact_id, confidence=0.9, user_id=\"u1\")","handlingStrategy":"type-guard","validationCode":"from deerflow.agents.memory.manager import MemoryManager\n\ndef supports_fact_update(manager: MemoryManager) -> bool:\n    return type(manager).update_fact is not MemoryManager.update_fact","typeGuard":"def supports_fact_update(manager: MemoryManager) -> bool:\n    \"\"\"True when the backend supports partial per-fact updates.\"\"\"\n    return type(manager).update_fact is not MemoryManager.update_fact","tryCatchPattern":"try:\n    memory = manager.update_fact(fact_id, content=new_text, user_id=uid)\nexcept NotImplementedError as e:\n    raise UnsupportedMemoryOperation(str(e)) from e","preventionTips":["Gate fact-edit actions on supports_fact_update() before rendering them.","For remote backends, correct facts conversationally (middleware extraction) instead of scripted update_fact calls.","Document per-backend CRUD matrices wherever memory.manager_class is configured."],"tags":["memory","not-implemented","crud","deerflow"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}