can1357/oh-my-pi · error · ValueError

{field} must be an integer

Error message

{field} must be an integer

What it means

`_optional_int` accepts absence but otherwise demands a JSON integer; it explicitly rejects booleans (checked first because bool subclasses int in Python) and rejects floats and strings. This keeps counts/indices/ids strictly integral.

Source

Thrown at python/omp-rpc/src/omp_rpc/protocol.py:263

        return tuple(items)
    raise ValueError(f"{field} must be a string or an array of strings")


def _optional_bool(payload: JsonObject, field: str) -> bool | None:
    value = payload.get(field)
    if value is None:
        return None
    if not isinstance(value, bool):
        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")

View on GitHub (pinned to 9690622007)

Solutions

  1. Coerce to int before parsing: int(float(value)) for floats, int(value) for numeric strings
  2. Fix the producer to emit JSON integers without decimal points
  3. Verify the key holds the intended field — a swapped key often explains a type surprise

Example fix

# before
payload = {"exit_code": "0"}
result = parse_bash_result(payload)  # ValueError: exit_code must be an integer
# after
payload = {"exit_code": int("0")}
result = parse_bash_result(payload)
Defensive patterns

Strategy: validation

Validate before calling

def coerce_optional_int(payload: dict, field: str) -> dict:
    value = payload.get(field)
    if value is not None and not isinstance(value, bool):
        if isinstance(value, float) and value.is_integer():
            payload[field] = int(value)
        elif isinstance(value, str) and value.lstrip("-").isdigit():
            payload[field] = int(value)
    if payload.get(field) is not None and not isinstance(payload[field], int):
        raise TypeError(f"{field!r} must be an integer, got {value!r}")
    return payload

parse_bash_result(coerce_optional_int(payload, "exit_code"))

Type guard

def is_optional_int(payload: dict, field: str) -> bool:
    value = payload.get(field)
    return value is None or (isinstance(value, int) and not isinstance(value, bool))

Try / catch

try:
    result = parse_bash_result(payload)
except ValueError as e:
    logger.warning("bash result had non-integer numeric field", extra={"error": str(e)})
    result = None

Prevention

When it happens

Trigger: parse_assistant_message_event, parse_bash_result, parse_extension_ui_request, or parse_notification receives a field like an exit code, token count, or message index as a float (3.0), a numeric string ("42"), or true/false.

Common situations: A producer serializes integers as floats (JavaScript numbers can arrive as 3.0 via some serializers); values passed through shell/CSV round-trips become strings; a boolean flag was put in an int 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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/c60ba7f6546f85c8. Report an issue: GitHub.