headroomlabs-ai/headroom · error · ValueError
expected a finite number, got {value!r}
Error message
expected a finite number, got {value!r} What it means
ValueError from _coerce in headroom/settings_store.py when a 'float' field receives a value that parses to a non-finite float — NaN, +inf, or -inf (math.isfinite check at line 785). Note the value arrives as a Python float here, so json.loads('Infinity') (which Python's json accepts by default) or float('nan') from a caller's parsing will trigger it. Surfaces via SettingsValidationError.field_errors.
Source
Thrown at headroom/settings_store.py:785
if field.type == "optional-bool" and token == "":
return None
if token in ("1", "true", "yes", "on"):
return True
if token in ("0", "false", "no", "off", ""):
return False
raise ValueError(f"expected a boolean, got {value!r}")
if field.type in ("int", "float"):
if isinstance(value, bool): # bool is an int subclass — reject explicitly
raise ValueError(f"expected a number, got {value!r}")
number: int | float
if field.type == "int":
if isinstance(value, float) and not value.is_integer():
raise ValueError(f"expected an integer, got {value!r}")
number = int(value)
else:
number = float(value)
if not math.isfinite(number):
raise ValueError(f"expected a finite number, got {value!r}")
if field.minimum is not None and number < field.minimum:
raise ValueError(f"must be >= {field.minimum}")
if field.maximum is not None and number > field.maximum:
raise ValueError(f"must be <= {field.maximum}")
return number
if field.type == "enum":
token = str(value)
if token not in field.choices:
raise ValueError(f"{token!r} not one of {list(field.choices)}")
return token
if field.type == "csv-list":
tokens = value if isinstance(value, list | tuple) else str(value).split(",")
tokens = [str(token).strip() for token in tokens]
tokens = [token for token in tokens if token]
return ",".join(tokens) if tokens else None
if field.type == "header-map":
if isinstance(value, dict):
parsed = valueView on GitHub (pinned to 322425c43b)
Solutions
- Fix the upstream computation so it never yields inf/NaN (guard divisions, use a large finite default).
- If the setting means 'no limit', use the field's documented maximum or omit it (null), not infinity.
- Validate with math.isfinite() before saving.
Example fix
# before
save({'timeout': float(x) / count}) # inf when count == 0
# after
save({'timeout': float(x) / count if count else 3600.0}) Defensive patterns
Strategy: validation
Validate before calling
import math
def finite_float(v) -> bool:
try:
return math.isfinite(float(v))
except (TypeError, ValueError):
return False Type guard
import math
def is_finite_number(v) -> bool:
return not isinstance(v, bool) and isinstance(v, (int, float)) and math.isfinite(v) Try / catch
except SettingsValidationError as e:
for key, msg in e.field_errors.items():
if 'finite' in msg:
payload.pop(key, None) # drop and fall back to default
store.save(payload) Prevention
- Reject non-standard JSON with parse_constant to catch Infinity/NaN at the boundary.
- Use math.isfinite as a final guard on any computed float destined for config.
When it happens
Trigger: save({'request_timeout': float('inf')}); a JSON payload containing Infinity/NaN literals (Python's json module accepts them); computed ratios like x/0.0 producing inf and then passed to the store.
Common situations: Division-by-zero bugs upstream that leak inf into config; numpy calculations returning np.inf/np.nan converted with float(); JSON produced by tools that emit non-standard Infinity literals.
Related errors
- expected an integer, got {value!r}
- expected a boolean, got {value!r}
- expected a number, got {value!r}
- must be >= {field.minimum}
- must be <= {field.maximum}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/d4d4f8a152dc4f68.
Report an issue: GitHub.