bytedance/deer-flow · error · ValueError
fact.confidence must be a number between 0 and 1
Error message
fact.confidence must be a number between 0 and 1
What it means
fact['confidence'] must be a real number in [0, 1]; the default is 0.5. Booleans are explicitly rejected even though bool subclasses int, and NaN fails the range check (NaN comparisons are false). Out-of-range numbers (1.5, -0.1) and strings ('0.8') also raise ValueError.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py:201
safely rebased after that shared revision changed.
"""
if not isinstance(fact, dict):
raise ValueError("fact must be an object")
normalized = copy.deepcopy(fact)
normalized["id"] = str(normalized.get("id") or f"fact_{uuid.uuid4().hex}")
# Validate the id through the canonical path builder's public contract.
if not normalized["id"] or any(character not in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" for character in normalized["id"]):
raise ValueError("fact.id may contain only letters, numbers, '_' and '-'")
normalized["schemaVersion"] = 2
if not isinstance(normalized.get("content"), str):
raise ValueError("fact.content must be a string")
normalized["content"] = normalized["content"].strip()
if not normalized["content"]:
raise ValueError("fact.content must not be empty")
_normalize_category(normalized)
confidence = normalized.get("confidence", 0.5)
if isinstance(confidence, bool) or not isinstance(confidence, (int, float)) or not 0 <= confidence <= 1:
raise ValueError("fact.confidence must be a number between 0 and 1")
normalized["confidence"] = float(confidence)
status = normalized.get("status", "active")
if status != "active":
raise ValueError("fact.status must be 'active'; deletion is physical")
normalized["status"] = "active"
normalized["scope"] = copy.deepcopy(scope)
_require_string_list(normalized, "topics")
_require_string_list(normalized, "consolidatedFrom")
revision = normalized.get("revision", 1)
if isinstance(revision, bool) or not isinstance(revision, int) or revision < 1:
raise ValueError("fact.revision must be an integer >= 1")
source = normalized.get("source")
if isinstance(source, str):
if source in {"manual", "consolidation", "import", "unknown"}:
normalized["source"] = {"type": source, "threadId": None}
else:
normalized["source"] = {"type": "conversation", "threadId": source}
elif not isinstance(source, dict):View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Normalize the scale before saving: divide by 100 when the numeric input is greater than 1.
- Map verbal levels: {'high': 0.9, 'medium': 0.5, 'low': 0.2}, or omit the key to accept the 0.5 default.
- Reject bool explicitly at the boundary since bool passes naive isinstance(x, (int, float)) checks.
Example fix
# before
memory.save_fact({"content": "...", "confidence": 85})
# after
memory.save_fact({"content": "...", "confidence": 0.85}) Defensive patterns
Strategy: validation
Validate before calling
c = fact.get("confidence", 0.5)
if isinstance(c, bool) or not isinstance(c, (int, float)) or not 0 <= c <= 1:
c = min(max(float(c), 0.0), 1.0) if not isinstance(c, bool) and isinstance(c, (int, float)) else 0.5
fact["confidence"] = c Type guard
import math
def is_valid_confidence(v: object) -> bool:
return not isinstance(v, bool) and isinstance(v, (int, float)) and math.isfinite(v) and 0 <= v <= 1 Prevention
- Convert percentage scales (0-100) to fractions at the boundary.
- Map verbal confidence ('high'/'low') to numbers before saving.
- Never pass booleans where confidence is expected.
When it happens
Trigger: Saving {'confidence': 'high'}, {'confidence': 85} (percent instead of fraction), {'confidence': True}, or float('nan').
Common situations: LLMs emitting confidence as a percentage or a word; producers using 0-100 scales; JSON configs with stringly-typed numbers.
Related errors
- 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
- fact.category must be a string
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/6c09eb45d34f72de.
Report an issue: GitHub.