can1357/oh-my-pi · error · RpcError

RPC message pagination repeated a cursor

Error message

RPC message pagination repeated a cursor

What it means

The pagination loop tracks seen_cursors to detect non-converging iteration. If get_messages_page returns a next_cursor that was already visited, the loop would otherwise spin forever, so the client raises this RpcError. It indicates the server's cursor is not advancing (or is cycling) between pages.

Source

Thrown at python/omp-rpc/src/omp_rpc/client.py:1044

                seen_cursors: set[str] = set()
                total_messages: int | None = None
                cursor: str | None = None
                while True:
                    page = self.get_messages_page(cursor=cursor, limit=256)
                    if (
                        total_messages is not None
                        and page.total_messages != total_messages
                    ):
                        raise RpcError(
                            "RPC message pagination returned an inconsistent total"
                        )
                    total_messages = page.total_messages
                    messages.extend(page.messages)
                    cursor = page.next_cursor
                    if cursor is None:
                        break
                    if cursor in seen_cursors:
                        raise RpcError("RPC message pagination repeated a cursor")
                    seen_cursors.add(cursor)
                if len(messages) != total_messages:
                    raise RpcError(
                        "RPC message pagination ended before the advertised total"
                    )
                return tuple(messages)
            except RpcCommandError as error:
                if error.command != "get_messages_page" or not (
                    error.code in _RPC_MESSAGES_PAGE_FALLBACK_CODES
                    or error.error
                    in (
                        _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")))

View on GitHub (pinned to 9690622007)

Solutions

  1. Upgrade the omp server to a build with correct cursor advancement
  2. Retry full pagination once the session is idle (concurrent mutation can invalidate cursors)
  3. If testing, make the mock server advance the cursor monotonically and terminate with nextCursor=None
  4. Catch RpcError and fall back to the non-paginated messages fetch if one exists

Example fix

# before: stub server always returns the same cursor
return {"messages": page, "totalMessages": n, "nextCursor": "abc"}  # loops forever

# after: advance or terminate the cursor
cursor = None if at_end else encode_offset(offset + len(page))
return {"messages": page, "totalMessages": n, "nextCursor": cursor}
Defensive patterns

Strategy: retry

Validate before calling

# basic server sanity check before paginating
page = client.get_messages_page(cursor=None, limit=1)
# a healthy server must terminate or advance; mocks must never echo cursors

Type guard

def cursor_advances(page, seen: set) -> bool:
    return page.next_cursor is None or page.next_cursor not in seen

Try / catch

try:
    messages = client.get_all_messages()
except RpcError as e:
    if "repeated a cursor" in str(e):
        messages = retry_pagination_or_fallback()  # restart once session idle
    else:
        raise

Prevention

When it happens

Trigger: Server returns the same next_cursor for consecutive get_messages_page calls — e.g. a buggy or mocked get_messages_page, a cursor invalidated by concurrent message mutation, or a server version whose cursor encoding changed.

Common situations: Older server build with a broken pagination cursor; custom/stub server that always echoes the same cursor; session state rewritten mid-pagination so the cursor points back to an earlier offset.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e8f1ec83c121a102. Report an issue: GitHub.