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
- Update the RPC server so its final cursor and totals match the returned rows.
- Retry when background history eviction/compaction is idle.
- Rely on the client's own page-fallback path, which retries with the monolithic get_messages command.
- 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
- Pause history eviction/compaction during history fetches.
- Upgrade the server so its final page matches the advertised total.
- Prefer the client's automatic page-fallback path.
- Cross-check page counts in server logs when it reproduces.
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
- RPC message pagination returned an inconsistent total
- bridge call {name!r} failed
- Host URI write failed for ${url.href}
- Client already started
- RPC message pagination repeated a cursor
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8bb7f488a0bc96e6.
Report an issue: GitHub.