can1357/oh-my-pi · error

RPC message page limit must be between 1 and ${MAX_RPC_MESSA

Error message

RPC message page limit must be between 1 and ${MAX_RPC_MESSAGE_PAGE_LIMIT}

What it means

pageRpcMessages validates the limit option: it must be a safe integer between 1 and 256 (MAX_RPC_MESSAGE_PAGE_LIMIT). Passing undefined uses the default (100); anything outside the range — 0, negative, non-integers, NaN, or >256 — throws this error.

Source

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

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);
		pageBytes += messageBytes;
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Clamp limit before calling: Math.min(Math.max(1, Math.floor(limit)), 256), or omit it to use the default 100.
  2. Convert string inputs to numbers first and reject NaN: const n = Number(raw); if (!Number.isSafeInteger(n)) omit or default.
  3. Use limit ≤ 256 and iterate pages with nextCursor instead of trying to fetch everything in one request.
  4. Guard UI/state code so limit can never become 0 or negative when computing page sizes.

Example fix

// before
const limit = Number(query.get('limit')); // NaN when absent
page(messages, snapshot, { limit });
// after
const raw = Number(query.get('limit'));
const limit = Number.isSafeInteger(raw) ? Math.min(Math.max(1, raw), 256) : undefined;
page(messages, snapshot, limit ? { limit } : {});
Defensive patterns

Strategy: validation

Validate before calling

function clampLimit(raw: unknown): number | undefined {
  const n = typeof raw === "string" ? Number(raw) : raw;
  return typeof n === "number" && Number.isSafeInteger(n) && n >= 1 && n <= 256 ? n : undefined;
}

Type guard

function isValidPageLimit(v: unknown): v is number {
  return typeof v === "number" && Number.isSafeInteger(v) && v >= 1 && v <= 256;
}

Try / catch

try {
  return page(messages, snapshot, { limit });
} catch (err) {
  if (String(err.message).startsWith("RPC message page limit")) {
    return page(messages, snapshot, {}); // fall back to default limit 100
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling pageRpcMessages / get_messages_page with limit: 0, limit: -1, limit: 1000, limit: 12.5, or limit: NaN; forwarding an unvalidated user-supplied query parameter as limit.

Common situations: Clients implementing 'fetch all' by passing a huge limit; parsing limit from a URL/string without Number() conversion ('20' as string fails Number.isSafeInteger? — actually strings fail the check); tests probing bounds; UI pagination math producing 0.

Related errors


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