mastra-ai/mastra · error
page value too large
Error message
page value too large
What it means
listMessages rejects page values whose computed offset (page * perPage) exceeds Number.MAX_SAFE_INTEGER / 2, because such offsets would break integer precision and cause severe performance issues in an in-memory store. The limit protects against astronomically large page numbers rather than normal pagination ranges.
Source
Thrown at packages/core/src/storage/domains/memory/inmemory.ts:139
if (threadIds.length === 0 || threadIds.some(id => !id.trim())) {
throw new Error('threadId must be a non-empty string or array of non-empty strings');
}
const threadIdSet = new Set(threadIds);
const { field, direction } = this.parseOrderBy(orderBy, 'ASC');
// Normalize perPage for query (false → MAX_SAFE_INTEGER, 0 → 0, undefined → 40)
const perPage = normalizePerPage(perPageInput, 40);
if (page < 0) {
throw new Error('page must be >= 0');
}
// Prevent unreasonably large page values that could cause performance issues
const maxOffset = Number.MAX_SAFE_INTEGER / 2;
if (page * perPage > maxOffset) {
throw new Error('page value too large');
}
// Calculate offset from page
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
// When perPage is 0 with no includes, there's nothing to return.
if (perPage === 0 && (!include || include.length === 0)) {
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
}
// Step 1: Get messages matching threadId(s) and optionally resourceId
let threadMessages = Array.from(this.db.messages.values()).filter((msg: any) => {
// Message must be in one of the specified threads
if (threadIdSet && !threadIdSet.has(msg.thread_id)) return false;
// If optionalResourceId provided, message must match it
if (optionalResourceId && msg.resourceId !== optionalResourceId) return false;
return true;
});View on GitHub (pinned to 75dd419e61)
Solutions
- Clamp page to a sane upper bound for your application (e.g. page < 1_000_000) before calling.
- Sanitize external pagination input: reject non-finite numbers and cap the value at the API boundary.
- Prefer cursor/keyset pagination for very deep datasets instead of huge page offsets.
Example fix
// before
await storage.listMessages({ threadId, page: Number(req.query.page) });
// after
const page = Math.min(Math.max(0, Number(req.query.page) || 0), 1_000_000);
await storage.listMessages({ threadId, page }); Defensive patterns
Strategy: validation
Validate before calling
const MAX_PAGE = 1_000_000;
const page = Math.min(Math.max(0, Number(rawPage) || 0), MAX_PAGE);
await storage.listMessages({ threadId, page }); Type guard
function isSafePage(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= 1_000_000;
} Prevention
- Cap externally supplied page numbers at an application-defined maximum.
- Reject non-finite input (Infinity, NaN) before arithmetic on page/perPage.
- Use keyset/cursor pagination for deep scans instead of huge offsets.
When it happens
Trigger: Calling listMessages with an absurd page number (e.g. page: Number.MAX_SAFE_INTEGER or a DoS-style crafted query param) combined with any perPage, such that page * perPage > MAX_SAFE_INTEGER / 2.
Common situations: Unvalidated API/query-string input forwarded straight to storage; attacker-supplied pagination params; tests probing boundary conditions.
Related errors
- threadId must be a non-empty string or array of non-empty st
- page must be >= 0
- COMPARE_INVALID_INPUT
- perPage must be >= 0
- page must be >= 0
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/be449340d88b4513.
Report an issue: GitHub.