mastra-ai/mastra · error
perPage must be false or a safe integer
Error message
perPage must be false or a safe integer
What it means
validatePaginationInput accepts perPage as a number or the literal false (meaning 'fetch all'). If perPageInput is neither false nor a finite safe integer, this error is thrown. Strings, null, undefined, Infinity, and NaN are all rejected.
Source
Thrown at packages/core/src/storage/domains/memory/base.ts:491
/**
* Validates pagination input before normalization.
* Use this when accepting raw perPageInput (number | false) from callers.
*
* When perPage is false (fetch all), page must be 0 since pagination is disabled.
* When perPage is a number, delegates to validatePagination for full validation.
*
* @param page - Page number (0-indexed)
* @param perPageInput - Items per page as number, or false to fetch all results
* @throws Error if perPageInput is false and page !== 0
* @throws Error if perPageInput is invalid (not false or a non-negative safe integer)
* @throws Error if page is invalid or offset would overflow
*/
protected validatePaginationInput(page: number, perPageInput: number | false): void {
// Validate perPageInput type first
if (perPageInput !== false) {
if (typeof perPageInput !== 'number' || !Number.isFinite(perPageInput) || !Number.isSafeInteger(perPageInput)) {
throw new Error('perPage must be false or a safe integer');
}
if (perPageInput < 0) {
throw new Error('perPage must be >= 0');
}
}
// When fetching all (perPage: false), only page 0 is valid
if (perPageInput === false) {
if (page !== 0) {
throw new Error('page must be 0 when perPage is false');
}
// Still validate page is a valid integer
if (!Number.isFinite(page) || !Number.isSafeInteger(page)) {
throw new Error('page must be >= 0');
}
return;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Parse and coerce: const perPage = raw === false ? false : Number.parseInt(raw, 10).
- Validate with (perPage === false || (Number.isSafeInteger(perPage) && perPage >= 0)) before calling.
- Use perPage: false explicitly (not null/undefined) when you want all records.
- Enable strict TypeScript checking so string|null values cannot reach the call site.
Example fix
// before
await storage.listThreads({ page: 0, perPage: req.query.perPage }); // string
// after
const raw = req.query.perPage;
const perPage = raw === 'all' ? false : Math.max(0, parseInt(raw, 10) || 0);
await storage.listThreads({ page: 0, perPage }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalizePerPage(raw) {
if (raw === false) return false;
const n = Number(raw);
return Number.isSafeInteger(n) && n >= 0 ? n : 10;
} Type guard
function isValidPerPageInput(p: unknown): p is number | false {
return p === false || (typeof p === 'number' && Number.isSafeInteger(p) && p >= 0);
} Try / catch
try {
await storage.listThreads({ page: 0, perPage });
} catch (e) {
if (e instanceof Error && e.message === 'perPage must be false or a safe integer') {
return storage.listThreads({ page: 0, perPage: 10 });
}
throw e;
} Prevention
- Parse query params before passing perPage (they arrive as strings)
- Use literal false, never null/undefined, for fetch-all
- Enable strict TS so invalid types cannot reach the call
When it happens
Trigger: Calling listThreads/listMessages with { perPage: '10' } (string from a query param), { perPage: null }, { perPage: undefined } typed as number, or { perPage: Infinity }.
Common situations: Passing unparsed query-string values (req.query always yields strings); JSON configs where perPage came through as null; TypeScript types bypassed via `as any` or JS callers.
Related errors
- Worker resourceLimits.${name} must be a positive safe intege
- GitHub cursor must be a positive page number.
- GitHub cursor must be a positive page number.
- ${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} name must be
- AGENT_LIST_SUSPENDED_RUNS_INVALID_PER_PAGE
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/832c5b4aacc324b8.
Report an issue: GitHub.