mastra-ai/mastra · error · Error
perPage must be >= 0
Error message
perPage must be >= 0
What it means
Storage's normalizePerPage() sanitizes pagination input before queries. Negative perPage values have no meaning, so the function throws 'perPage must be >= 0'. Zero is allowed (returns zero results) and undefined falls back to a default; only strictly negative numbers are rejected.
Source
Thrown at packages/core/src/storage/base.ts:135
void _domainKeysExhaustive;
/**
* Normalizes perPage input for pagination queries.
*
* @param perPageInput - The raw perPage value from the user
* @param defaultValue - The default perPage value to use when undefined (typically 40 for messages, 100 for threads)
* @returns A numeric perPage value suitable for queries (false becomes MAX_SAFE_INTEGER)
* @throws Error if perPage is a negative number
*/
export function normalizePerPage(perPageInput: number | false | undefined, defaultValue: number): number {
if (perPageInput === false) {
return Number.MAX_SAFE_INTEGER; // Get all results
} else if (perPageInput === 0) {
return 0; // Return zero results
} else if (typeof perPageInput === 'number' && perPageInput > 0) {
return perPageInput; // Valid positive number
} else if (typeof perPageInput === 'number' && perPageInput < 0) {
throw new Error('perPage must be >= 0');
}
// For undefined, use default
return defaultValue;
}
/**
* Calculates pagination offset and prepares perPage value for response.
* When perPage is false (fetch all), offset is always 0 regardless of page.
*
* @param page - The page number (0-indexed)
* @param perPageInput - The original perPage input (number, false for all, or undefined)
* @param normalizedPerPage - The normalized perPage value (from normalizePerPage)
* @returns Object with offset for query and perPage for response
*/
export function calculatePagination(
page: number,
perPageInput: number | false | undefined,
normalizedPerPage: number,View on GitHub (pinned to 75dd419e61)
Solutions
- Clamp the value before the call: perPage: Math.max(0, desiredPerPage).
- If 'all results' was intended, omit perPage or pass undefined (library applies its default / MAX_SAFE_INTEGER path) rather than a huge/negative number.
- Guard computed values — if a subtraction can go negative, fall back to 0 or undefined.
- Sanitize external/user input with a coercion helper before passing to storage APIs.
Example fix
// before
const remaining = total - offset;
await storage.listThreads({ perPage: remaining }); // negative on last page
// after
const remaining = Math.max(0, total - offset);
await storage.listThreads({ perPage: remaining }); Defensive patterns
Strategy: validation
Validate before calling
function safePerPage(value, fallback) {
if (value === undefined || value === null) return fallback;
const n = Number(value);
if (!Number.isFinite(n) || n < 0) return fallback;
return Math.floor(n);
}
// use: await storage.listThreads({ perPage: safePerPage(input.perPage, 10) }) Type guard
function isValidPerPage(v) {
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
} Try / catch
try {
return await storage.listThreads({ ...opts, perPage: opts.perPage });
} catch (e) {
if (String(e?.message) === 'perPage must be >= 0') {
return storage.listThreads({ ...opts, perPage: undefined }); // fall back to default
}
throw e;
} Prevention
- Clamp computed perPage values with Math.max(0, value) — especially total-minus-offset math.
- Sanitize user-supplied pagination before passing it to storage APIs.
- Omit perPage entirely when you want the library default or 'all results'.
- Add a shared pagination helper for the whole app so perPage is normalized in one place.
When it happens
Trigger: Calling any storage listing/query API (threads, messages, traces, workflows, etc.) whose options include perPage (via helpers like perPage, normalizedPerPage, perPageForQuery) with a negative number, e.g. { perPage: -1 } or perPage computed as items.length - offset when offset > items.length.
Common situations: Computing perPage as a difference (remaining = total - offset) that goes negative on the last page; passing user-supplied pagination params straight through without clamping; frontend pagination bug where pageSize becomes negative after a filter change.
Related errors
- page must be >= 0
- page value too large
- Invalid knowledge node cursor.
- page must be >= 0
- page value too large
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2486fc25e7658526.
Report an issue: GitHub.