can1357/oh-my-pi · error · ValueError
{field} must be a number
Error message
{field} must be a number What it means
`_optional_float` accepts absence but otherwise requires a JSON number (int or float), rejecting booleans explicitly and strings/nulls. The value is normalized to float on success. This guards numeric stats like cost or duration.
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:272
raise ValueError(f"{field} must be a boolean")
return value
def _optional_int(payload: JsonObject, field: str) -> int | None:
value = payload.get(field)
if value is None:
return None
if isinstance(value, bool) or not isinstance(value, int):
raise ValueError(f"{field} must be an integer")
return value
def _optional_float(payload: JsonObject, field: str) -> float | None:
value = payload.get(field)
if value is None:
return None
if isinstance(value, bool) or not isinstance(value, (int, float)):
raise ValueError(f"{field} must be a number")
return float(value)
def _tuple_of_strings(values: object, *, field: str) -> tuple[str, ...] | None:
if values is None:
return None
if not isinstance(values, list):
raise ValueError(f"{field} must be a list")
result: list[str] = []
for item in values:
if not isinstance(item, str):
raise ValueError(f"{field} must contain only strings")
result.append(item)
return tuple(result) or None
def _parse_agent_message(payload: JsonObject, *, field: str) -> AgentMessage:View on GitHub (pinned to 9690622007)
Solutions
- Strip formatting and convert: float(value.replace("$", "")) or float(value) for numeric strings
- Fix the producer to emit raw JSON numbers
- If precision matters, agree on a string-encoded decimal schema and update the parser, not the payload ad hoc
Example fix
# before
payload = {"total_cost": "1.25"}
state = parse_session_state(payload) # ValueError: total_cost must be a number
# after
payload = {"total_cost": float("1.25")}
state = parse_session_state(payload) Defensive patterns
Strategy: validation
Validate before calling
def ensure_optional_number(payload: dict, field: str) -> None:
value = payload.get(field)
if value is None:
return
if isinstance(value, bool) or not isinstance(value, (int, float)):
raise TypeError(f"{field!r} must be a number, got {value!r}")
ensure_optional_number(payload, "total_cost")
parse_session_state(payload) Type guard
def is_optional_number(payload: dict, field: str) -> bool:
value = payload.get(field)
return value is None or (isinstance(value, (int, float)) and not isinstance(value, bool)) Try / catch
try:
state = parse_session_state(payload)
except ValueError as e:
logger.error("session stats field not numeric", extra={"payload": payload, "error": str(e)})
state = None Prevention
- Send raw JSON numbers, not formatted strings ("$1.25", "1,250.00")
- Keep numeric formatting for display only, never on the wire
- Exclude bools from numeric fields (bool subclasses int)
- Agree on fixed-vs-float representation for money across client and server
When it happens
Trigger: parse_session_state receives a numeric stat field (e.g. total cost) as a string "$1.25" or "1.25", a bool, or a Decimal-like object that is not int/float.
Common situations: Currency or metric values serialized as formatted strings by the producer; values passed through JSON with custom encoders producing strings; a placeholder bool in a numeric field.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- {field} must be a string
- {field} must be a boolean
- {field}[{index}] must be a string
- {field} must be a string or an array of strings
- {field} must be an integer
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/18ec476d914367c3.
Report an issue: GitHub.