can1357/oh-my-pi · warning

RPC message pagination returned an inconsistent total

Error message

RPC message pagination returned an inconsistent total

What it means

The paginated get-messages loop validates each page's totalMessages: it must be a safe non-negative integer and must not change across pages. A missing, malformed, or shifting total means the server's message set mutated mid-pagination or the page is malformed, so the client aborts rather than return corrupt results (the caller's isPageFallbackError path then falls back to the single get_messages command).

Source

Thrown at packages/coding-agent/src/modes/rpc/rpc-client.ts:883

		return this.#getData<RpcMessagesPage>(response);
	}

	/** Get all messages, draining stable pages when protocol v2 is available. */
	async getMessages(): Promise<AgentMessage[]> {
		if (this.#protocolVersion === 2) {
			try {
				const messages: AgentMessage[] = [];
				const seenCursors = new Set<string>();
				let totalMessages: number | undefined;
				let cursor: string | undefined;
				do {
					const page = await this.getMessagesPage({ cursor, limit: 256 });
					if (
						!Number.isSafeInteger(page.totalMessages) ||
						page.totalMessages < 0 ||
						(totalMessages !== undefined && page.totalMessages !== totalMessages)
					)
						throw new Error("RPC message pagination returned an inconsistent total");
					totalMessages = page.totalMessages;
					messages.push(...page.messages);
					cursor = page.nextCursor;
					if (cursor && seenCursors.has(cursor)) throw new Error("RPC message pagination repeated a cursor");
					if (cursor) seenCursors.add(cursor);
				} while (cursor);
				if (messages.length !== totalMessages)
					throw new Error("RPC message pagination ended before the advertised total");
				return messages;
			} catch (error) {
				if (!isPageFallbackError(error)) throw error;
			}
		}
		const response = await this.#send({ type: "get_messages" });
		return this.#getData<{ messages: AgentMessage[] }>(response).messages;
	}

	/**

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry after the session quiesces (no messages being written).
  2. Check the server/RPC implementation emits a stable, integer totalMessages on every page.
  3. Update client and server to matching versions so the pagination contract holds.
  4. Let the built-in fallback run: the loop catches page-fallback errors and retries with the plain get_messages command.

Example fix

// before
const msgs = await client.getMessages(); // fetched while agent streams
// after
await agentIdlePromise; // wait until session stops writing
const msgs = await client.getMessages();
Defensive patterns

Strategy: retry

Validate before calling

function pageLooksValid(page: { totalMessages: unknown }): boolean {
  return typeof page.totalMessages === "number" &&
    Number.isSafeInteger(page.totalMessages) && page.totalMessages >= 0;
}

Type guard

function isPaginated(page: unknown): page is { messages: unknown[]; totalMessages: number; nextCursor: string | null } {
  return typeof page === "object" && page !== null &&
    typeof (page as { totalMessages?: unknown }).totalMessages === "number";
}

Try / catch

try {
  const msgs = await client.getMessages();
} catch (err) {
  if ((err as Error).message.startsWith("RPC message pagination")) {
    await sessionIdle;
    const msgs = await client.getMessages(); // client has a get_messages fallback
  } else throw err;
}

Prevention

When it happens

Trigger: Iterating getMessagesPage({cursor, limit: 256}) where a page returns totalMessages undefined/non-integer/negative, or a different value than the previous page (messages appended/removed while paginating).

Common situations: An active session keeps appending messages while history is being fetched; a server bug emitting inconsistent totals; an RPC peer that doesn't fully implement the pagination contract.

Related errors


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