crewAIInc/crewAI · error · ValueError
seconds must be a number, got NaN.
Error message
seconds must be a number, got NaN.
What it means
WaitTool normalizes requested wait durations through a validation helper. It explicitly rejects NaN (math.isnan) because NaN comparisons are always False, so an uncapped NaN would silently pass the max_seconds cap check; the ValueError names the exact defect.
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/wait_tool/wait_tool.py:175
def _resolve_duration(self, seconds: float) -> tuple[float, bool]:
"""Validate and clamp the requested duration to ``max_seconds``.
``BaseTool.run`` skips ``args_schema`` validation when called with
positional arguments, so the bounds are enforced here too rather than
left to ``time.sleep`` to reject. Infinity is a valid request: it clamps
to the cap like any other oversized wait.
Args:
seconds: The requested wait duration.
Returns:
A tuple of the duration to actually wait and whether it was capped.
Raises:
ValueError: If ``seconds`` is negative or not a number.
"""
if math.isnan(seconds):
raise ValueError("seconds must be a number, got NaN.")
if seconds < 0:
raise ValueError(f"seconds must be zero or greater, got {seconds:g}.")
if seconds > self.max_seconds:
return self.max_seconds, True
return seconds, False
def _format_result(
self, waited: float, requested: float, reason: str | None
) -> str:
"""Describe the completed wait back to the model.
Args:
waited: The duration actually waited.
requested: The duration the model asked for.
reason: Optional note on what is being waited for.
Returns:
A summary of how long was waited and whether the request was capped.View on GitHub (pinned to 754d7323be)
Solutions
- Sanitize numeric inputs before calling the tool: use a helper that rejects/replaces NaN (e.g., 0.0) with math.isnan.
- Fix the upstream computation producing NaN (guard zero divisors, fillna() in pandas).
- Tighten the tool schema/format so model output cannot be NaN (strict JSON parsing: json.loads rejects NaN unless parse_constant allows it).
Example fix
# before
import math
seconds = float('nan') # e.g. from model output 'NaN'
tool.run(seconds=seconds) # ValueError: got NaN
# after
seconds = seconds if (seconds is not None and not math.isnan(seconds)) else 0.0
tool.run(seconds=seconds) Defensive patterns
Strategy: validation
Validate before calling
import math
def safe_seconds(v) -> float:
try:
f = float(v)
except (TypeError, ValueError):
return 0.0
return 0.0 if math.isnan(f) else f
# seconds = safe_seconds(model_output) before WaitTool Type guard
import math
def is_valid_seconds(v) -> bool:
try:
f = float(v)
except (TypeError, ValueError):
return False
return not math.isnan(f) and f >= 0 Try / catch
try:
tool.run(seconds=raw)
except ValueError as e:
if 'NaN' in str(e):
tool.run(seconds=0.0) # sane default, log the bad input
else:
raise Prevention
- Sanitize all model-provided numerics through float() + isnan/isinf checks.
- Use strict JSON parsing (json.loads rejects NaN literals).
- Centralize numeric coercion in one helper used by every tool boundary.
When it happens
Trigger: An LLM emitting a tool call like wait(seconds='NaN') that parses to float('nan'), or user code computing seconds as 0/0, float('nan'), or a NaN from math operations (math.inf - math.inf) and passing it to WaitTool.
Common situations: Model-generated JSON with the literal token NaN (accepted by Python's float() but invalid strict JSON); arithmetic upstream producing NaN (division by zero in a stat that feeds the wait); NaN leaking through pandas/numpy values passed unconverted.
Related errors
- seconds must be zero or greater, got {seconds:g}.
- Project name '{name}' would generate folder name '{folder_na
- Project name '{name}' contains no valid characters for a Pyt
- Project name '{name}' would generate class name '{class_name
- Project name '{name}' would generate class name '{class_name
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/1f685bab6a21d306.
Report an issue: GitHub.