bytedance/deer-flow · error · ValueError
content
Error message
content
What it means
create_memory_fact strips the content argument and raises ValueError('content') when the result is empty. Whitespace-only strings are treated as absent content, because a fact with no text is unstoreable and would also collide on the normalized-content duplicate key.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:928
confidence wins, confidence coerced). If the cap evicts the just-added
(lower-confidence) fact, ``fact_id`` is ``None`` so callers report
"not stored - cap reached" instead of a dangling id with a false
"added" status. This restores both the max_facts cap and the post-trim
existence check (upstream's ``create_memory_fact_with_created_fact``),
which the vendored copy had dropped together to avoid the dangling id.
Duplicate rejection is enforced here (not only by callers): the
candidate's normalized content key is checked against the fresh
memory snapshot inside the revision-conflict retry loop of both
storage paths (apply_changes and legacy single-file save), so
concurrent creators cannot both store the same content. Raises
``ValueError("Duplicate fact")`` on a normalized-content match.
"""
if agent_name is None:
raise ValueError("agent_name")
normalized_content = content.strip()
if not normalized_content:
raise ValueError("content")
normalized_category = category.strip() or "context"
validated_confidence = _validate_confidence(confidence)
candidate_key = _fact_content_key(normalized_content)
now = utc_now_iso_z()
fact_id = f"fact_{uuid.uuid4().hex[:8]}"
candidate = {
"id": fact_id,
"content": normalized_content,
"category": normalized_category,
"confidence": validated_confidence,
"createdAt": now,
"source": "manual",
}
if getattr(type(self._storage), "apply_changes", None) is not MemoryStorage.apply_changes:
for attempt in range(3):
memory_data = self.get_memory_data(agent_name, user_id=user_id) if attempt == 0 else self.reload_memory_data(agent_name, user_id=user_id)
# Duplicate rejection lives inside the conflict-retry loop so
# it is re-evaluated against the fresh snapshot after everyView on GitHub (pinned to 1dd6ba1acb)
Solutions
- Validate and reject blank input before calling: if not content or not content.strip(): return error
- Trim input at the API boundary so downstream code sees normalized text
- If the value comes from an LLM, add a retry/check for empty extraction results
Example fix
// before
fact_id = memory.create_memory_fact(content=user_text, agent_name=agent).1
// after
if not user_text or not user_text.strip():
raise HTTPException(400, "content must not be empty")
_, fact_id = memory.create_memory_fact(content=user_text.strip(), agent_name=agent) Defensive patterns
Strategy: validation
Validate before calling
normalized = (content or "").strip()
if not normalized:
raise HTTPException(400, "content must not be empty") Type guard
def is_nonblank(value: str | None) -> TypeGuard[str]:
return isinstance(value, str) and bool(value.strip()) Try / catch
try:
memory.create_memory_fact(content, agent_name=agent)
except ValueError as e:
if str(e) == "content":
raise HTTPException(400, "content must not be empty")
raise Prevention
- Trim and check user/model input at the API boundary
- Treat whitespace-only extraction results as 'nothing to store', not as facts
When it happens
Trigger: Calling create_memory_fact('') or create_memory_fact(' \n '), or forwarding user/LLM input that was never checked for blankness (empty form field, model returned empty string).
Common situations: Memory-add tool wired directly to a chat input with no required-field validation, or an extraction prompt whose model output collapses to whitespace.
Related errors
- fact.content must not be empty
- retrieval fact.id must be a non-empty string
- retrieval fact.content must be a non-empty string
- unsupported FTS5 retrieval mode: {mode}
- retrieval category filter must be a string
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/c580b35ca91db7ab.
Report an issue: GitHub.