{"record":{"id":"91a76d931122b365","repo":"commaai/openpilot","slug":"32602","errorCode":"-32602","errorMessage":"params must be a list, object, or omitted","messagePattern":"params must be a list, object, or omitted","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"warning","filePath":"openpilot/system/athena/rpc.py","lineNumber":87,"sourceCode":"  if isinstance(err, str):\n    return err\n  if isinstance(err, dict):\n    data = err.get(\"data\")\n    if isinstance(data, dict) and data.get(\"message\"):\n      return str(data[\"message\"])\n    if err.get(\"message\") is not None:\n      return str(err[\"message\"])\n  return str(err)\n\n\ndef _invoke(fn: Callable[..., Any], params: Any) -> Any:\n  if params is None:\n    return fn()\n  if isinstance(params, dict):\n    return fn(**params)\n  if isinstance(params, (list, tuple)):\n    return fn(*params)\n  raise TypeError(\"params must be a list, object, or omitted\")\n\n\ndef handle(raw: str | bytes | JsonDict, methods: MethodMap | None = None) -> str:\n  methods = dispatcher if methods is None else methods\n\n  try:\n    msg = raw if isinstance(raw, dict) else loads(raw)\n  except (TypeError, ValueError, UnicodeDecodeError):\n    return dumps_error(None, \"parse error\", PARSE_ERROR)\n\n  if not is_call(msg):\n    raise ValueError(\"not a call\")\n\n  req_id = msg.get(\"id\")\n  name = msg.get(\"method\")\n  if not isinstance(name, str):\n    return dumps_error(req_id, \"invalid request\", INVALID_REQUEST)\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/system/athena/rpc.py#L69-L105","documentation":"TypeError (JSON-RPC -32602, invalid params) from rpc._invoke: the 'params' member of a request was present but was neither an object, an array, nor null. Per JSON-RPC 2.0 params must be by-position (array) or by-name (object); anything else cannot be bound to the method signature.","triggerScenarios":"Sending params as a bare string, number, or boolean, e.g. {\"method\":\"getMessage\",\"params\":\"carState\"} or params=1000. _invoke checks None/dict/(list,tuple) and raises TypeError otherwise.","commonSituations":"Clients abbreviating single-argument calls as a bare value instead of a one-element list or an object; generated SDKs typing params loosely; hand-built request dicts.","solutions":["Pass positional args as an array: \"params\": [\"carState\"]","Pass named args as an object: \"params\": {\"service\": \"carState\"}","Omit params entirely for zero-argument methods; never send a scalar params value"],"exampleFix":"// before\n{\"jsonrpc\": \"2.0\", \"method\": \"getMessage\", \"params\": \"carState\", \"id\": 1}\n\n// after\n{\"jsonrpc\": \"2.0\", \"method\": \"getMessage\", \"params\": {\"service\": \"carState\"}, \"id\": 1}","handlingStrategy":"type-guard","validationCode":"def valid_rpc_params(params) -> bool:\n    return params is None or isinstance(params, (dict, list))","typeGuard":"from typing import Any\n\ndef is_valid_params(params: Any) -> bool:\n    return params is None or isinstance(params, (dict, list, tuple))","tryCatchPattern":"try:\n    handle(raw, dispatcher)\nexcept TypeError as e:\n    if 'params must be a list' in str(e):\n        fix_client_payload_shape()  # params was a scalar/string\n    raise","preventionTips":["Always wrap params: scalars become [value] or {'name': value}","Validate outgoing requests against the JSON-RPC 2.0 spec before sending"],"tags":["jsonrpc","json","validation","api-contract"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}