can1357/oh-my-pi · error · ValueError
{field}[{index}] must be a string
Error message
{field}[{index}] must be a string What it means
`_optional_str_list` accepts a field that is absent, a single string, or an array of strings. When an array is supplied, every element must be a string; this error fires naming the offending index, reporting exactly which element was invalid (`field[index]`).
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:243
def _optional_str_list(payload: JsonObject, field: str) -> tuple[str, ...]:
"""Parse an optional string-or-array-of-strings field.
The agent's `systemPrompt` (and similar) became `string[]` server-side
when multi-prompt support landed. Older daemons still emit a bare string,
so we accept either shape. Returns an empty tuple when the field is
absent or null.
"""
value = payload.get(field)
if value is None:
return ()
if isinstance(value, str):
return (value,)
if isinstance(value, list):
items: list[str] = []
for index, item in enumerate(value):
if not isinstance(item, str):
raise ValueError(f"{field}[{index}] must be a string")
items.append(item)
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 NoneView on GitHub (pinned to 9690622007)
Solutions
- Look at the index in the message, coerce that element to a string, and re-parse
- Normalize the array before parsing: [str(x) for x in value]
- Fix the producer so every element is a JSON string
Example fix
# before
payload = {"todos": ["a", 2, "b"]}
state = parse_session_state(payload) # ValueError: todos[1] must be a string
# after
payload = {"todos": [str(x) for x in ["a", 2, "b"]]}
state = parse_session_state(payload) Defensive patterns
Strategy: validation
Validate before calling
def ensure_str_list_items(payload: dict, field: str) -> None:
value = payload.get(field)
if isinstance(value, list):
for i, item in enumerate(value):
if not isinstance(item, str):
raise TypeError(f"{field}[{i}] must be a string, got {item!r}")
ensure_str_list_items(payload, "todos")
parse_session_state(payload) Type guard
def is_str_or_str_list(value: object) -> bool:
if isinstance(value, str):
return True
return isinstance(value, list) and all(isinstance(x, str) for x in value) Try / catch
try:
state = parse_session_state(payload)
except ValueError as e:
if "must be a string" in str(e):
field = str(e).split("[")[0]
payload[field] = [str(x) for x in payload.get(field, [])]
state = parse_session_state(payload)
else:
raise Prevention
- Normalize arrays to strings at the producer boundary
- Avoid mixed-type lists in wire protocols
- Add per-element schema validation for list fields
- Round-trip test fixtures through the parser in CI
When it happens
Trigger: parse_session_state receives a list field where one element is a number, null, bool, or nested object — e.g. `["a", 3, "b"]` fails at index 1.
Common situations: A producer mixes numeric and string IDs in an array; JSON from another language serializes mixed-type lists; a fixture was hand-edited and one entry lost its quotes.
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} must be a string or an array of strings
- {field} must be an integer
- {field} must be a number
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/deb51852f1f393ab.
Report an issue: GitHub.