bytedance/deer-flow · error · ValueError
memory_data.{section}
Error message
memory_data.{section} What it means
During import, each summaries section memory_data['user'] and memory_data['history'] must itself be a dict (missing keys default to {}). The f-string message names the offending section ('memory_data.user' or 'memory_data.history'). The check runs per section before merging into the empty template, so nothing is persisted when it fires.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:821
def get_memory_data(self, agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Get the current memory data via the injected storage."""
return self._storage.load(agent_name, user_id=user_id)
def reload_memory_data(self, agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Reload memory data via the injected storage."""
return self._storage.reload(agent_name, user_id=user_id)
def import_memory_data(self, memory_data: dict[str, Any], agent_name: str | None = None, *, user_id: str | None = None) -> dict[str, Any]:
"""Persist imported memory data via the injected storage."""
if not isinstance(memory_data, dict):
raise ValueError("memory_data")
memory_data = copy.deepcopy(memory_data)
empty = create_empty_memory()
for section in ("user", "history"):
incoming_section = memory_data.get(section, {})
if not isinstance(incoming_section, dict):
raise ValueError(f"memory_data.{section}")
complete_section = copy.deepcopy(empty[section])
for key, value in incoming_section.items():
if key in complete_section and isinstance(complete_section[key], dict) and isinstance(value, dict):
complete_section[key].update(copy.deepcopy(value))
else:
complete_section[key] = copy.deepcopy(value)
memory_data[section] = complete_section
if agent_name is not None and getattr(type(self._storage), "apply_changes", None) is not MemoryStorage.apply_changes:
current = self.get_memory_data(agent_name, user_id=user_id)
incoming_facts = copy.deepcopy(memory_data.get("facts", []))
if not isinstance(incoming_facts, list) or any(not isinstance(fact, dict) for fact in incoming_facts):
raise ValueError("memory_data.facts")
for fact in incoming_facts:
fact["id"] = str(fact.get("id") or f"fact_{uuid.uuid4().hex}")
fact["confidence"] = _coerce_source_confidence(fact)
current_by_id = {str(fact.get("id")): fact for fact in current.get("facts", []) if isinstance(fact, dict)}
incoming_ids = {str(fact.get("id")) for fact in incoming_facts}
self._storage.apply_changes(View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Make each section an object: {'user': {'name': ...}, 'history': {'summary': ...}}.
- Convert legacy list-shaped history into the dict shape at import time (e.g. {'messages': [...]}) before calling import_memory_data.
- Validate the upload with a pydantic model declaring user/history as dict fields.
Example fix
# before
updater.import_memory_data({"user": "likes tea", "history": []}, agent_name=a)
# after
updater.import_memory_data({"user": {"preferences": "likes tea"}, "history": {"messages": []}}, agent_name=a) Defensive patterns
Strategy: type-guard
Validate before calling
for section in ("user", "history"):
value = memory_data.get(section, {})
if not isinstance(value, dict):
raise HTTPException(400, f"memory_data.{section} must be an object") Type guard
def has_valid_summary_sections(doc: object) -> TypeGuard[dict[str, Any]]:
return isinstance(doc, dict) and all(
isinstance(doc.get(section, {}), dict) for section in ("user", "history")
) Prevention
- Define 'user' and 'history' as object schemas in the import/export format docs.
- Convert legacy list-shaped history sections at import time.
- Validate uploads with a pydantic model declaring user/history as dict.
When it happens
Trigger: import_memory_data({'user': 'friendly assistant', ...}) where the section is a plain string; {'history': [...messages...]} as a list; JSON exports where these sections were flattened into arrays or strings.
Common situations: Older export formats storing history as a message list; hand-written import files; LLM-generated memory documents putting prose in 'user' instead of a structured profile dict.
Related errors
- memory_data
- memory_data.facts
- retrieval fact.id must be a non-empty string
- retrieval fact.content must be a non-empty string
- unsupported FTS5 retrieval mode: {mode}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/04763f1d7b348347.
Report an issue: GitHub.