can1357/oh-my-pi · error · RpcError
RPC response payload must be an object
Error message
RPC response payload must be an object
What it means
_clone_json_object validates that an incoming RPC response/result payload is a JSON object (dict) before cloning it. It is called on response paths (_request, stdout loop events, protocol-error building), so a server response whose payload is an array, string, or null triggers this RpcError.
Source
Thrown at python/omp-rpc/src/omp_rpc/client.py:299
def _clone_json_value(value: object) -> JsonValue:
if value is None or isinstance(value, (str, int, float, bool)):
return cast(JsonValue, value)
if isinstance(value, list):
return [_clone_json_value(item) for item in value]
if isinstance(value, dict):
cloned: JsonObject = {}
for key, item in value.items():
if not isinstance(key, str):
raise RpcError("RPC payload objects must use string keys")
cloned[key] = _clone_json_value(item)
return cloned
raise RpcError("RPC payload must be JSON-serializable")
def _clone_json_object(value: object) -> JsonObject:
if not isinstance(value, dict):
raise RpcError("RPC response payload must be an object")
return cast(JsonObject, _clone_json_value(value))
class RpcError(RuntimeError):
"""Base exception for the Python RPC client."""
class RpcTimeoutError(RpcError):
"""Raised when the server does not respond before a timeout."""
class RpcProcessExitError(RpcError):
"""Raised when the RPC process exits while a request is pending."""
class RpcConcurrencyError(RpcError):
"""Raised when overlapping prompt lifecycle collectors would be ambiguous."""
View on GitHub (pinned to 9690622007)
Solutions
- Verify server and client protocol versions match; align the response schema to one that returns objects.
- Inspect raw frames (stderr/logs) to see the actual payload shape being returned.
- If you control the server, wrap results in an object: {"items": [...] } instead of [...].
- Check for intermediaries (proxies, logging shims) transforming the response.
Example fix
// before: server returns a bare array
result = [1, 2, 3]
// after: return an object envelope
result = {"items": [1, 2, 3]} Defensive patterns
Strategy: try-catch
Type guard
def is_object_payload(payload) -> bool:
return isinstance(payload, dict) Try / catch
try:
result = await client.request(method, params)
except RpcError as exc:
if "response payload must be an object" in str(exc):
logger.error("server returned non-object payload; check protocol version")
else:
raise Prevention
- Pin client and server to compatible protocol versions
- Ensure server results are always JSON objects
- Log raw frames when integrating a new server
When it happens
Trigger: The server replies with a non-object result/event payload, e.g. a bare array or null where the protocol expects an object, and the client clones it in _request or _read_stdout_loop.
Common situations: Version mismatch where an older/newer server returns a different response shape; a proxy or shim rewriting responses; custom agent returning a plain list as the result field.
Related errors
- Replacement text is not valid UTF-8: {err}
- rpc frame must be an object
- invalid glob `{pattern}`: {error}
- xAI device-code response was not a JSON object.
- ${label} was not a JSON object
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d02c1d16b9308e50.
Report an issue: GitHub.