can1357/oh-my-pi · error · RpcError
get_messages_page response has an invalid totalMessages
Error message
get_messages_page response has an invalid totalMessages
What it means
_parse_messages_page validates the raw get_messages_page payload before constructing MessagesPage. totalMessages must be a true non-negative int (bools excluded since bool subclasses int in Python); otherwise the client raises this RpcError. It protects callers from servers returning malformed or schema-drifted pagination responses.
Source
Thrown at python/omp-rpc/src/omp_rpc/client.py:1074
_RPC_MESSAGES_PAGE_BUSY_ERROR,
_RPC_MESSAGES_PAGE_STALE_ERROR,
)
):
raise
payload = self._request("get_messages")
return parse_agent_messages(cast(JsonValue | None, payload.get("messages")))
def get_messages_page(
self, *, cursor: str | None = None, limit: int | None = None
) -> MessagesPage:
payload = self._request("get_messages_page", cursor=cursor, limit=limit)
raw_total = payload.get("totalMessages")
if (
not isinstance(raw_total, int)
or isinstance(raw_total, bool)
or raw_total < 0
):
raise RpcError("get_messages_page response has an invalid totalMessages")
raw_cursor = payload.get("nextCursor")
if raw_cursor is not None and not isinstance(raw_cursor, str):
raise RpcError("get_messages_page response has an invalid nextCursor")
return MessagesPage(
messages=parse_agent_messages(
cast(JsonValue | None, payload.get("messages"))
),
total_messages=raw_total,
next_cursor=raw_cursor,
)
def set_custom_tools(self, tools: Sequence[HostTool[Any, Any]]) -> tuple[str, ...]:
self._custom_tools = tuple(tools)
if self._process is None:
return tuple(tool.name for tool in self._custom_tools)
payload = self._request(
"set_host_tools",View on GitHub (pinned to 9690622007)
Solutions
- Upgrade client and server to matching versions so the response schema aligns
- Fix the mock/stub server to return totalMessages as a non-negative integer
- Log the raw payload to identify the actual field name/type the server sends
- If a proxy rewrites responses, bypass or correct it
Example fix
# before: stub returns a string total
return {"messages": [], "totalMessages": "3", "nextCursor": None}
# after
return {"messages": [], "totalMessages": 3, "nextCursor": None} Defensive patterns
Strategy: type-guard
Validate before calling
def valid_total(payload: dict) -> bool:
t = payload.get("totalMessages")
return isinstance(t, int) and not isinstance(t, bool) and t >= 0
Type guard
def is_valid_total(v: object) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v >= 0
Try / catch
try:
page = client.get_messages_page(cursor=None, limit=256)
except RpcError as e:
if "invalid totalMessages" in str(e):
page = None # schema mismatch: upgrade server or fix the stub
else:
raise
Prevention
- Return totalMessages as a JSON integer in servers/mocks (never a string or bool)
- Keep client/server versions in sync
- Add contract tests asserting the get_messages_page response schema
- Beware proxies that re-serialize numbers as strings
When it happens
Trigger: Server responds to get_messages_page with totalMessages missing, null, a string, a float, a bool, or a negative number — typically a server/client version skew or a stub server returning an unexpected shape.
Common situations: Custom or mocked RPC servers with sloppy payloads; older server builds whose field was named differently (e.g. 'total'); proxies that re-serialize numbers as strings.
Related errors
- set_model returned an empty payload
- get_messages_page response has an invalid nextCursor
- set_host_tools response did not include toolNames
- set_host_uri_schemes response did not include schemes
- RPC message pagination returned an inconsistent total
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/dbe776f117f6309a.
Report an issue: GitHub.