{"record":{"id":"9a566d939895ad2a","repo":"can1357/oh-my-pi","slug":"rpc-message-pagination-ended-before-the-advertised-9a566d","errorCode":null,"errorMessage":"RPC message pagination ended before the advertised total","messagePattern":"RPC message pagination ended before the advertised total","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":1047,"sourceCode":"                while True:\n                    page = self.get_messages_page(cursor=cursor, limit=256)\n                    if (\n                        total_messages is not None\n                        and page.total_messages != total_messages\n                    ):\n                        raise RpcError(\n                            \"RPC message pagination returned an inconsistent total\"\n                        )\n                    total_messages = page.total_messages\n                    messages.extend(page.messages)\n                    cursor = page.next_cursor\n                    if cursor is None:\n                        break\n                    if cursor in seen_cursors:\n                        raise RpcError(\"RPC message pagination repeated a cursor\")\n                    seen_cursors.add(cursor)\n                if len(messages) != total_messages:\n                    raise RpcError(\n                        \"RPC message pagination ended before the advertised total\"\n                    )\n                return tuple(messages)\n            except RpcCommandError as error:\n                if error.command != \"get_messages_page\" or not (\n                    error.code in _RPC_MESSAGES_PAGE_FALLBACK_CODES\n                    or error.error\n                    in (\n                        _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","sourceCodeStart":1029,"sourceCodeEnd":1065,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L1029-L1065","documentation":"After the cursor loop ends (next_cursor became None), the client compares the accumulated message count with the advertised total_messages and raises this RpcError if fewer were received. The server claimed N total messages but stopped paging early, so the transcript would be silently truncated without this check.","triggerScenarios":"Server reports totalMessages=N but the final page's nextCursor becomes None after fewer than N messages were returned — e.g. messages dropped/compacted between pages, a page handler that silently truncates, or duplicated-cursor paths skipped after the seen_cursors guard.","commonSituations":"Server-side compaction removing messages mid-pagination; server bug returning oversized pages that drop items; mismatch between the total computed at page 1 and what later pages actually contain.","solutions":["Retry the pagination from the start once the session is idle","Upgrade the server; this is usually a server-side pagination defect","Log per-page counts and totals to identify which page lost messages","If compaction is expected, use a server version that reports totals consistent with compacted state"],"exampleFix":"# before: trusting a single pass against a mutating session\nmessages = client.get_all_messages()\n\n# after: reconcile with the current state before paging\nclient.wait_until_idle()  # or poll state until no active run\nmessages = client.get_all_messages()","handlingStrategy":"retry","validationCode":"first = client.get_messages_page(cursor=None, limit=256)\nexpected = first.total_messages\n# compare later against len(collected); retry if the session is still active\n","typeGuard":null,"tryCatchPattern":"try:\n    messages = client.get_all_messages()\nexcept RpcError as e:\n    if \"ended before the advertised total\" in str(e):\n        messages = client.get_all_messages()  # one clean re-read after settling\n    else:\n        raise\n","preventionTips":["Wait for session idle before collecting the full transcript","Investigate server-side compaction/pruning if totals shrink mid-read","Upgrade the server if pages systematically return fewer items than the total","Count per-page messages in logs to locate the loss point"],"tags":["rpc","pagination","data-loss","consistency"],"backgroundTag":"pagination-incomplete-result","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}