can1357/oh-my-pi · warning

RPC message pagination ended before the advertised total

Error message

RPC message pagination ended before the advertised total

What it means

After the do/while pagination loop finishes (cursor is falsy), the client asserts messages.length === totalMessages. Fewer messages than advertised means pages ended early — dropped pages or a total computed over a different set — so the client throws instead of returning partial history.

Source

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

				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;
	}

	/**
	 * Get list of OAuth providers available for login, with their current authentication status.
	 */
	async getLoginProviders(): Promise<Array<{ id: string; name: string; available: boolean; authenticated: boolean }>> {
		const response = await this.#send({ type: "get_login_providers" });
		return this.#getData<{
			providers: Array<{ id: string; name: string; available: boolean; authenticated: boolean }>;
		}>(response).providers;
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Update the RPC server so its final cursor and totals match the returned rows.
  2. Retry when background history eviction/compaction is idle.
  3. Rely on the client's own page-fallback path, which retries with the monolithic get_messages command.
  4. Verify with server logs how many messages each page returned.

Example fix

// before
const all = await client.getMessages(); // during compaction
// after
await compactionIdle;
const all = await client.getMessages();
Defensive patterns

Strategy: retry

Try / catch

try {
  const msgs = await client.getMessages();
} catch (err) {
  if ((err as Error).message.includes("ended before the advertised total")) {
    await backgroundJobsIdle;
    const msgs = await client.getMessages();
  } else throw err;
}

Prevention

When it happens

Trigger: The last page returns nextCursor=null but the accumulated messages array is shorter than the advertised totalMessages (server skipped a page, filtered rows silently, or the total counted messages never returned).

Common situations: Server-side truncation/eviction of history between total computation and page reads; a buggy or older RPC host implementation; mid-fetch message compaction.

Related errors


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