{"record":{"id":"bfdc37c3b9548f91","repo":"can1357/oh-my-pi","slug":"messages-must-be-a-list","errorCode":null,"errorMessage":"messages must be a list","messagePattern":"messages must be a list","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/protocol.py","lineNumber":315,"sourceCode":"def _parse_assistant_message(payload: JsonObject, *, field: str) -> AssistantMessage:\n    message = _parse_agent_message(payload, field=field)\n    if message.get(\"role\") != \"assistant\":\n        raise ValueError(f\"{field}.role must be 'assistant'\")\n    return cast(AssistantMessage, message)\n\n\ndef _parse_tool_result_message(payload: JsonObject, *, field: str) -> ToolResultMessage:\n    message = _parse_agent_message(payload, field=field)\n    if message.get(\"role\") != \"toolResult\":\n        raise ValueError(f\"{field}.role must be 'toolResult'\")\n    return cast(ToolResultMessage, message)\n\n\ndef parse_agent_messages(payload: JsonValue | None) -> tuple[AgentMessage, ...]:\n    if payload is None:\n        return ()\n    if not isinstance(payload, list):\n        raise ValueError(\"messages must be a list\")\n\n    messages: list[AgentMessage] = []\n    for index, item in enumerate(payload):\n        messages.append(\n            _parse_agent_message(\n                _clone_json_object(item, field=f\"messages[{index}]\"),\n                field=f\"messages[{index}]\",\n            )\n        )\n    return tuple(messages)\n\n\ndef parse_assistant_message_event(payload: JsonObject) -> AssistantMessageEvent:\n    event_type = _require_literal(\n        payload.get(\"type\"),\n        _ASSISTANT_MESSAGE_EVENT_TYPE_VALUES,\n        field=\"assistantMessageEvent.type\",\n    )","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/protocol.py#L297-L333","documentation":"parse_agent_messages expects a JSON array of agent messages (or null, meaning empty). It raises this error when the payload is any other JSON type (object, string, number, bool). The library throws so the following per-item loop can safely index and parse each element.","triggerScenarios":"Calling parse_agent_messages with a single message object instead of a list; a server returning a wrapped object like {\"messages\": [...]} instead of the bare array; passing a dict from an RPC response field that should have been an array.","commonSituations":"Passing response['messages'] vs response directly; older server versions returning a different envelope; hand-constructed payloads in tests.","solutions":["Unwrap the payload to the actual list before calling (e.g. payload[\"messages\"])","Wrap a single message in a list: [message]","Check the server response shape against the protocol docs and fix the emitter or the extraction point","Handle null explicitly if absence should mean empty"],"exampleFix":"// before\nparse_agent_messages(result[\"messages\"])\n// after\nparse_agent_messages(result)","handlingStrategy":"validation","validationCode":"if payload is not None and not isinstance(payload, list):\n    raise TypeError(\"expected a list of messages (or None)\")","typeGuard":"from typing import TypeGuard\n\ndef is_message_list(v: object) -> TypeGuard[list]:\n    return isinstance(v, list)","tryCatchPattern":"try:\n    messages = parse_agent_messages(payload)\nexcept ValueError:\n    messages = ()  # or unwrap payload[\"messages\"] and retry","preventionTips":["Confirm the RPC response field is the bare array, not an envelope object","Treat None as an empty message list","Validate response shape once at the transport layer"],"tags":["protocol","validation","json"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}