bytedance/deer-flow · error · ValueError
agent_name is required to upsert a fact
Error message
agent_name is required to upsert a fact
What it means
MemoryStorage.upsert_fact() requires agent_name because it delegates to apply_changes, which writes to the agent-scoped fact file. The guard fires before the fact is deep-copied or an id is generated, so a failed call has no side effects and no id is consumed.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:1323
"complete": False,
"version": memory_file.get("version", DOCUMENT_VERSION),
"revision": memory_file.get("revision", 0),
"lastUpdated": memory_file.get("lastUpdated", ""),
"upsertedFacts": [copy.deepcopy(value) for action, value, _ in notifications if action == "upsert" and isinstance(value, dict)],
"deletedFactIds": [str(value) for action, value, _ in notifications if action == "remove"],
}
def upsert_fact(
self,
fact: dict[str, Any],
*,
user_id: str | None = None,
agent_name: str | None = None,
expected_manifest_revision: int | None = None,
expected_fact_revision: int | None = None,
) -> dict[str, Any]:
if agent_name is None:
raise ValueError("agent_name is required to upsert a fact")
incoming = copy.deepcopy(fact)
incoming["id"] = str(incoming.get("id") or f"fact_{uuid.uuid4().hex}")
fact_id = incoming["id"]
return self.apply_changes(
{"upserts": [incoming], "upsertRevisions": {fact_id: expected_fact_revision}},
user_id=user_id,
agent_name=agent_name,
expected_manifest_revision=expected_manifest_revision,
allow_manifest_rebase=True,
)
def delete_fact(
self,
fact_id: str,
*,
user_id: str | None = None,
agent_name: str | None = None,
expected_manifest_revision: int | None = None,View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Thread the agent identity through: storage.upsert_fact(fact, agent_name=agent_name, user_id=user_id).
- If upserting outside any agent is a real use case, route it to your own scoped 'default' agent name rather than None.
- Make agent_name a required positional/keyword in your wrapper so it cannot be silently dropped.
Example fix
# before
def remember(fact: dict):
storage.upsert_fact(fact, user_id=user_id)
# after
def remember(fact: dict, *, agent_name: str):
storage.upsert_fact(fact, agent_name=agent_name, user_id=user_id) Defensive patterns
Strategy: validation
Validate before calling
if agent_name is None:
raise HTTPException(400, "agent_name required")
storage.upsert_fact(fact, agent_name=agent_name, user_id=user_id) Prevention
- Make agent_name required (no default) in wrapper signatures.
- Bind memory writes to the active agent context object rather than passing scopes manually.
- Default to a named sentinel agent instead of None when no agent context exists.
When it happens
Trigger: storage.upsert_fact({'content': ...}) with agent_name omitted - typically a generic 'save fact' service method that only received the fact payload.
Common situations: A memory-extraction step running outside an agent context; refactor that lost the agent identity; defaulting agent_name=None in a wrapper signature and never overriding it.
Related errors
- agent_name is required to persist facts
- agent_name is required to get a fact
- agent_name is required to delete a fact
- retrieval fact.id must be a non-empty string
- retrieval fact.content must be a non-empty string
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/ee074bc3c64d4072.
Report an issue: GitHub.