{"record":{"id":"958bd1c1f1e0cb0b","repo":"bytedance/deer-flow","slug":"agent-name-is-required-for-fact-repository-changes","errorCode":null,"errorMessage":"agent_name is required for fact repository changes","messagePattern":"agent_name is required for fact repository changes","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py","lineNumber":730,"sourceCode":"        upserts: list[dict[str, Any]],\n        deletes: list[str],\n        summaries: dict[str, Any] | None,\n        expected_revision: int | None,\n        delete_revisions: dict[str, int] | None = None,\n        upsert_revisions: dict[str, int | None] | None = None,\n    ) -> tuple[dict[str, Any], list[RetrievalNotification]]:\n        \"\"\"Commit only the addressed fact files plus the shared summary JSON.\n\n        Callers hold both locks and have already run journal recovery.  This is\n        deliberately not implemented as load-all/replace-all: unchanged fact\n        files are neither opened for backup nor rewritten nor re-indexed.\n        \"\"\"\n        current_memory = self._load_memory_file(path)\n        current_revision = int((current_memory or {}).get(\"revision\") or 0)\n        if expected_revision is not None and expected_revision != current_revision:\n            raise MemoryManifestRevisionConflict(f\"Expected user-memory revision {expected_revision}, found {current_revision}\")\n        if (upserts or deletes) and agent_name is None:\n            raise ValueError(\"agent_name is required for fact repository changes\")\n\n        scope = _scope_dict(user_id, agent_name)\n        prepared: dict[str, tuple[dict[str, Any], dict[str, Any] | None, Path]] = {}\n        for incoming in upserts:\n            if not isinstance(incoming, dict):\n                raise ValueError(\"change_set.upserts must contain fact objects\")\n            candidate = copy.deepcopy(incoming)\n            candidate[\"id\"] = str(candidate.get(\"id\") or f\"fact_{uuid.uuid4().hex}\")\n            fact_id = candidate[\"id\"]\n            if fact_id in prepared:\n                raise ValueError(f\"Duplicate fact id {fact_id!r} in upserts\")\n            if agent_name is None:  # guarded above\n                raise ValueError(\"agent_name is required for fact repository changes\")\n            existing, fact_path = self._read_fact(path, fact_id, user_id=user_id, agent_name=agent_name)\n            if upsert_revisions is not None and fact_id in upsert_revisions:\n                expected_fact_revision = upsert_revisions[fact_id]\n                if expected_fact_revision is None and existing is not None:\n                    raise MemoryFactRevisionConflict(f\"Fact {fact_id!r} must not already exist\")","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py#L712-L748","documentation":"Error \"agent_name is required for fact repository changes\" thrown in bytedance/deer-flow.","triggerScenarios":"Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:730 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Provide agent_name in the repository call or config before applying changes.","Use the agent-scoped memory API which supplies agent_name automatically."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}