can1357/oh-my-pi · error · ValueError
{field} must be a string or an array of strings
Error message
{field} must be a string or an array of strings What it means
`_optional_str_list` raises this when the field is present but is neither a string nor a list of strings — e.g. a number, boolean, or object. It is the top-level shape check before per-element validation.
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:246
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 None
if isinstance(value, bool) or not isinstance(value, int):
raise ValueError(f"{field} must be an integer")
return valueView on GitHub (pinned to 9690622007)
Solutions
- Print the payload field and confirm its type; wrap scalars in a list or fix the shape
- Convert dicts to their keys/values as a string list if that is the intended semantics
- Update client and server to matching protocol versions
Example fix
# before
payload = {"tags": {"a": 1}}
state = parse_session_state(payload) # ValueError: tags must be a string or an array of strings
# after
payload = {"tags": list({"a": 1}.keys())}
state = parse_session_state(payload) Defensive patterns
Strategy: validation
Validate before calling
def ensure_str_or_str_list(payload: dict, field: str) -> None:
value = payload.get(field)
if value is None:
return
if isinstance(value, str):
return
if isinstance(value, list) and all(isinstance(x, str) for x in value):
return
raise TypeError(f"{field!r} must be a string or list of strings, got {value!r}")
ensure_str_or_str_list(payload, "tags")
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:
logger.error("session state shape mismatch", extra={"payload": payload, "error": str(e)})
raise ProtocolError("incompatible session state payload") from e Prevention
- Match the documented wire schema for each field exactly
- Convert dicts/objects to the expected scalar-or-list shape before sending
- Keep a protocol schema test suite that validates sample payloads
- Coordinate field-type changes across client and server versions
When it happens
Trigger: parse_session_state receives an optional string-list field whose value is an int, dict, or other structure — e.g. `"tags": {"a": 1}` or `"tags": 7`.
Common situations: A schema change turned a string field into an object; the producer sent a single dict instead of a list; a client bug passed the wrong key's value into the payload.
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 an integer
- {field} must be a number
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/36e95897148b6243.
Report an issue: GitHub.