can1357/oh-my-pi · error

RPC message snapshot does not match current messages

Error message

RPC message snapshot does not match current messages

What it means

pageRpcMessages compares snapshot.messageCount with the actual messages array length; they must match because the cursor pins a specific stable snapshot. This error means the message list changed between when the snapshot was taken and when the page was requested, so the snapshot is no longer valid.

Source

Thrown at packages/coding-agent/src/modes/rpc/rpc-messages.ts:99

	return { version, sessionId, leafId, messageCount, offset };
}

function sameSnapshot(cursor: RpcMessageCursorPayload, snapshot: RpcMessageSnapshot): boolean {
	return (
		cursor.sessionId === snapshot.sessionId &&
		cursor.leafId === snapshot.leafId &&
		cursor.messageCount === snapshot.messageCount
	);
}

/** Page one stable in-memory message snapshot without crossing the v1 frame budget. */
export function pageRpcMessages(
	messages: readonly AgentMessage[],
	snapshot: RpcMessageSnapshot,
	options: RpcMessagesPageOptions = {},
): RpcMessagesPage {
	if (snapshot.messageCount !== messages.length)
		throw new Error("RPC message snapshot does not match current messages");
	const limit = options.limit ?? DEFAULT_RPC_MESSAGE_PAGE_LIMIT;
	if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_RPC_MESSAGE_PAGE_LIMIT)
		throw new Error(`RPC message page limit must be between 1 and ${MAX_RPC_MESSAGE_PAGE_LIMIT}`);
	let offset = 0;
	if (options.cursor !== undefined) {
		const cursor = decodeCursor(options.cursor);
		if (!sameSnapshot(cursor, snapshot))
			throw new RpcMessagesPageError(RPC_MESSAGES_PAGE_STALE_ERROR, "stale_cursor");
		offset = cursor.offset;
	}

	const page: AgentMessage[] = [];
	let pageBytes = 2;
	while (offset + page.length < messages.length && page.length < limit) {
		const message = messages[offset + page.length];
		const messageBytes = Buffer.byteLength(JSON.stringify(message), "utf8") + (page.length === 0 ? 0 : 1);
		if (page.length > 0 && pageBytes + messageBytes > MAX_RPC_MESSAGE_PAGE_BYTES) break;
		page.push(message);

View on GitHub (pinned to 9690622007)

Solutions

  1. Wait until the session is idle (agent_end / willContinue false) before paging messages.
  2. Re-fetch a fresh snapshot (and discard old cursors) whenever the message count changes — cursors are snapshot-bound and not valid across snapshots.
  3. Catch this error, refresh snapshot + messages, and retry the page request against the new snapshot.
  4. Use the structured error handling path: this raw Error indicates a caller bug/race, unlike RpcMessagesPageError which has a wire code — fix the calling code to snapshot and page atomically.

Example fix

// before
const snapshot = { sessionId, leafId, messageCount: messages.length };
await runAgent(); // messages grows
page(messages, snapshot); // mismatch
// after
await runAgent();
const snapshot = { sessionId, leafId, messageCount: messages.length };
page(messages, snapshot); // snapshot taken after messages stabilized
Defensive patterns

Strategy: try-catch

Validate before calling

function snapshotMatches(messages: readonly unknown[], snapshot: RpcMessageSnapshot): boolean {
  return snapshot.messageCount === messages.length;
}
if (!snapshotMatches(messages, snapshot)) {
  ({ messages, snapshot } = refreshSnapshot()); // re-capture before paging
}

Try / catch

try {
  return pageRpcMessages(messages, snapshot, opts);
} catch (err) {
  if (err.message === "RPC message snapshot does not match current messages") {
    const fresh = getFreshSnapshotAndMessages();
    return pageRpcMessages(fresh.messages, fresh.snapshot, {}); // old cursor is void
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling get_messages/page while the agent is actively appending messages so messages.length differs from the snapshot's messageCount; reusing an old snapshot with a mutated message list; concurrent requests during an agent run.

Common situations: A client pages a live session mid-run instead of waiting for agent_end; the caller built the snapshot once but passed a different messages array; a race between snapshot capture and paging in multi-request clients.

Related errors


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