{"record":{"id":"dbe776f117f6309a","repo":"can1357/oh-my-pi","slug":"get-messages-page-response-has-an-invalid-totalmes","errorCode":null,"errorMessage":"get_messages_page response has an invalid totalMessages","messagePattern":"get_messages_page response has an invalid totalMessages","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":1074,"sourceCode":"                        _RPC_MESSAGES_PAGE_BUSY_ERROR,\n                        _RPC_MESSAGES_PAGE_STALE_ERROR,\n                    )\n                ):\n                    raise\n        payload = self._request(\"get_messages\")\n        return parse_agent_messages(cast(JsonValue | None, payload.get(\"messages\")))\n\n    def get_messages_page(\n        self, *, cursor: str | None = None, limit: int | None = None\n    ) -> MessagesPage:\n        payload = self._request(\"get_messages_page\", cursor=cursor, limit=limit)\n        raw_total = payload.get(\"totalMessages\")\n        if (\n            not isinstance(raw_total, int)\n            or isinstance(raw_total, bool)\n            or raw_total < 0\n        ):\n            raise RpcError(\"get_messages_page response has an invalid totalMessages\")\n        raw_cursor = payload.get(\"nextCursor\")\n        if raw_cursor is not None and not isinstance(raw_cursor, str):\n            raise RpcError(\"get_messages_page response has an invalid nextCursor\")\n        return MessagesPage(\n            messages=parse_agent_messages(\n                cast(JsonValue | None, payload.get(\"messages\"))\n            ),\n            total_messages=raw_total,\n            next_cursor=raw_cursor,\n        )\n\n    def set_custom_tools(self, tools: Sequence[HostTool[Any, Any]]) -> tuple[str, ...]:\n        self._custom_tools = tuple(tools)\n        if self._process is None:\n            return tuple(tool.name for tool in self._custom_tools)\n\n        payload = self._request(\n            \"set_host_tools\",","sourceCodeStart":1056,"sourceCodeEnd":1092,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L1056-L1092","documentation":"_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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: stub returns a string total\nreturn {\"messages\": [], \"totalMessages\": \"3\", \"nextCursor\": None}\n\n# after\nreturn {\"messages\": [], \"totalMessages\": 3, \"nextCursor\": None}","handlingStrategy":"type-guard","validationCode":"def valid_total(payload: dict) -> bool:\n    t = payload.get(\"totalMessages\")\n    return isinstance(t, int) and not isinstance(t, bool) and t >= 0\n","typeGuard":"def is_valid_total(v: object) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 0\n","tryCatchPattern":"try:\n    page = client.get_messages_page(cursor=None, limit=256)\nexcept RpcError as e:\n    if \"invalid totalMessages\" in str(e):\n        page = None  # schema mismatch: upgrade server or fix the stub\n    else:\n        raise\n","preventionTips":["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"],"tags":["rpc","response-validation","schema-mismatch","pagination"],"backgroundTag":"rpc-response-schema-invalid","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}