can1357/oh-my-pi · error · ValueError
{field} must be a list
Error message
{field} must be a list What it means
`_optional_json_objects` parses an optional field that must be a JSON array of objects, returning None when the value is None. It raises this ValueError when the value is present but is not a list — commonly because a single object was supplied instead of wrapping it in an array. Items are additionally validated as objects via `_clone_json_object` with field name `{field}[]`.
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:176
def _clone_json_object(value: object, *, field: str) -> JsonObject:
if not isinstance(value, dict):
raise ValueError(f"{field} must be an object")
return cast(JsonObject, _clone_json_value(value, field=field))
def _optional_json_object(value: object, *, field: str) -> JsonObject | None:
if value is None:
return None
return _clone_json_object(value, field=field)
def _optional_json_objects(
values: object, *, field: str
) -> tuple[JsonObject, ...] | None:
if values is None:
return None
if not isinstance(values, list):
raise ValueError(f"{field} must be a list")
return tuple(_clone_json_object(item, field=f"{field}[]") for item in values)
def _clone_json_objects(values: object, *, field: str) -> tuple[JsonObject, ...]:
if values is None:
return ()
if not isinstance(values, list):
raise ValueError(f"{field} must be a list")
return tuple(_clone_json_object(item, field=f"{field}[]") for item in values)
def _require_literal(value: object, allowed: frozenset[str], *, field: str) -> str:
if not isinstance(value, str) or value not in allowed:
expected = ", ".join(sorted(allowed))
raise ValueError(f"{field} must be one of: {expected}")
return value
View on GitHub (pinned to 9690622007)
Solutions
- Wrap single objects in a list before parsing: pass `[obj]` instead of `obj`.
- If the value may be absent, pass None (or omit it) rather than an empty dict, so the optional path returns None cleanly.
- Compare the payload shape against the current protocol schema in omp_rpc/protocol.py to confirm the expected `list[object]` shape.
- Check for client/daemon version mismatch if the field shape recently changed upstream.
Example fix
// before
parse_extension_ui_request({"method": "select", "widgets": {"id": 1}})
// ValueError: widgets must be a list
// after
parse_extension_ui_request({"method": "select", "widgets": [{"id": 1}]}) Defensive patterns
Strategy: type-guard
Validate before calling
def is_json_object_list(value) -> bool:
return value is None or (
isinstance(value, list)
and all(isinstance(item, dict) for item in value)
)
assert is_json_object_list(payload.get(field)), f"{field} must be a list of objects" Type guard
def is_object_list(value: object) -> bool:
return isinstance(value, list) and all(isinstance(item, dict) for item in value) Try / catch
try:
req = parse_extension_ui_request(raw)
except ValueError as exc:
if "must be a list" in str(exc):
# auto-wrap a lone object if that's the common caller mistake
raw[field] = [raw[field]] if isinstance(raw.get(field), dict) else []
req = parse_extension_ui_request(raw)
else:
raise Prevention
- Wrap single objects in a list at construction time — the field is always plural.
- Prefer passing None over empty dicts for absent optional fields.
- Check the payload shape against the protocol schema after any client upgrade.
- Normalize tuples from other libraries with list(...) before parsing.
When it happens
Trigger: `parse_extension_ui_request` receiving e.g. `"options": {"a": 1}` (a single object) or `"options": "a,b"` (a string) where a list of objects is required: `[{'a': 1}]`. Also occurs when the field is accidentally omitted-safe None but a truthy non-list like a dict is supplied.
Common situations: Client sends one element without array brackets; a config file specifies a map instead of a list; an older daemon/client version uses a different shape for the field; hand-written payloads in tests forgot the list wrapper.
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 an object
- RPC frame must be a JSON object
- {field} must be JSON-serializable
- {field} must be one of: {expected}
- Unsupported language '{value}'. Supported: {}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/78020bf3cc05cf1e.
Report an issue: GitHub.