bytedance/deer-flow · error · ValueError
confidence
Error message
confidence
What it means
_validate_confidence() enforces that a fact's confidence is a finite number in [0, 1] before it is persisted, so stored JSON stays standards-compliant (no NaN/Infinity) and downstream max()/comparison arithmetic is safe. math.isfinite(NaN) is False and out-of-range values are rejected. The terse 'confidence' message is the deliberate contract.
Source
Thrown at backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/updater.py:54
# context. Unlike the previous asyncio.run() approach, this runs *sync*
# model.invoke() calls — no event loop is created, so the langchain async
# httpx client pool (globally cached via @lru_cache) is never touched and
# cross-loop connection reuse is impossible.
_SYNC_MEMORY_UPDATER_EXECUTOR = concurrent.futures.ThreadPoolExecutor(
max_workers=4,
thread_name_prefix="memory-updater-sync",
)
atexit.register(lambda: _SYNC_MEMORY_UPDATER_EXECUTOR.shutdown(wait=False))
# Data-access + fact-CRUD functions (_save_memory_to_file / get_memory_data /
# reload_memory_data / import_memory_data / clear_memory_data / create_memory_fact /
# delete_memory_fact / update_memory_fact) moved into MemoryUpdater as instance
# methods (use self._storage). See the class below.
def _validate_confidence(confidence: float) -> float:
"""Validate persisted fact confidence so stored JSON stays standards-compliant."""
if not math.isfinite(confidence) or confidence < 0 or confidence > 1:
raise ValueError("confidence")
return confidence
def _coerce_source_confidence(fact: dict[str, Any]) -> float:
"""Return a stored fact's confidence as a finite float in [0, 1], defaulting to 0.5.
dict.get(key, default) returns the stored value (including None) when the key
exists, so a fact written with "confidence": null would propagate None into
arithmetic and crash max(). This helper guards against null, bool, non-numeric,
and non-finite values from corrupted or manually edited memory files.
"""
raw = fact.get("confidence")
if raw is None or isinstance(raw, bool):
return 0.5
try:
val = float(raw)
except (TypeError, ValueError):
return 0.5View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Clamp and coerce before saving: confidence = min(1.0, max(0.0, float(confidence))).
- If the source uses percentages, divide by 100 at the boundary.
- Guard NaN explicitly: if not math.isfinite(x): use the 0.5 default.
- Validate the whole fact with a pydantic model using Field(ge=0, le=1, allow_inf_nan=False).
Example fix
# before
fact = {"content": text, "confidence": llm_score} # llm_score in 0..100 or NaN
# after
score = float(llm_score) if llm_score is not None and math.isfinite(float(llm_score)) else 0.5
fact = {"content": text, "confidence": min(1.0, max(0.0, score / 100.0 if score > 1 else score))} Defensive patterns
Strategy: validation
Validate before calling
def safe_confidence(raw) -> float:
try:
value = float(raw)
except (TypeError, ValueError):
return 0.5
if not math.isfinite(value):
return 0.5
if value > 1 and value <= 100: # percentage heuristic
value /= 100.0
return min(1.0, max(0.0, value))
fact["confidence"] = safe_confidence(fact.get("confidence")) Type guard
def is_valid_confidence(v: object) -> TypeGuard[float]:
return isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) and 0 <= v <= 1 Prevention
- Normalize LLM confidence scores (often 0-100 or 0-10) to [0,1] at extraction time.
- Use pydantic Field(ge=0, le=1, allow_inf_nan=False) on fact models.
- Default missing/invalid confidence to 0.5 instead of propagating NaN.
When it happens
Trigger: create/update fact paths passing confidence=float('nan'), float('inf'), -0.5, 1.2, or a non-float that reaches math.isfinite (e.g. a string if type coercion was skipped upstream).
Common situations: LLM emitting confidence as a percentage (0-100) instead of a fraction; parsing confidence from user input or JSON strings like '0.8'; NaN leaking from arithmetic on missing values (0/0).
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/4e70161c17ce0655.
Report an issue: GitHub.