mastra-ai/mastra · error
perPage must be >= 0
Error message
perPage must be >= 0
What it means
validatePagination rejects a perPage argument that is negative, non-finite, or not a safe integer. perPage of 0 is explicitly allowed and returns empty results; any negative value throws. This guards the offset computation page * perPage.
Source
Thrown at packages/core/src/storage/domains/memory/base.ts:459
throw new Error(`Metadata key "${key}" exceeds maximum length of ${MAX_METADATA_KEY_LENGTH} characters.`);
}
}
}
/**
* Validates pagination parameters and returns safe offset.
* @param page - Page number (0-indexed)
* @param perPage - Items per page (0 is allowed and returns empty results)
* @throws Error if page is negative, perPage is negative/invalid, or offset would overflow
*/
protected validatePagination(page: number, perPage: number): void {
if (!Number.isFinite(page) || !Number.isSafeInteger(page) || page < 0) {
throw new Error('page must be >= 0');
}
// perPage: 0 is allowed (returns empty results), negative values are rejected
if (!Number.isFinite(perPage) || !Number.isSafeInteger(perPage) || perPage < 0) {
throw new Error('perPage must be >= 0');
}
// Skip overflow check when perPage is 0 (no offset needed)
if (perPage === 0) {
return;
}
// Prevent overflow when calculating offset
const offset = page * perPage;
if (!Number.isSafeInteger(offset) || offset > Number.MAX_SAFE_INTEGER) {
throw new Error('page value too large');
}
}
/**
* Validates pagination input before normalization.
* Use this when accepting raw perPageInput (number | false) from callers.
*View on GitHub (pinned to 75dd419e61)
Solutions
- Clamp perPage: Math.max(0, Math.floor(Number(perPage))).
- Use perPage: false to fetch all records instead of a sentinel negative value.
- Validate with Number.isSafeInteger(perPage) && perPage >= 0 before calling.
- Fix the pageSize derivation so it cannot go negative.
Example fix
// before
await storage.listThreads({ page: 0, perPage: total - offset }); // can be negative
// after
const perPage = Math.max(0, total - offset);
await storage.listThreads({ page: 0, perPage }); Defensive patterns
Strategy: validation
Validate before calling
function safePerPage(raw) {
const n = Number(raw);
return Number.isSafeInteger(n) && n >= 0 ? n : 10;
} Type guard
function isValidPerPage(p: unknown): p is number {
return typeof p === 'number' && Number.isSafeInteger(p) && p >= 0;
} Try / catch
try {
await storage.listThreads({ page, perPage: safePerPage(rawPerPage) });
} catch (e) {
if (e instanceof Error && e.message === 'perPage must be >= 0') {
return storage.listThreads({ page, perPage: 10 });
}
throw e;
} Prevention
- Use perPage: false for fetch-all instead of negative sentinels
- Clamp derived page sizes with Math.max(0, x)
- Validate env-configured page sizes at startup
When it happens
Trigger: Calling listThreads/listMessages with { perPage: -10 }, { perPage: NaN }, or { perPage: 2.5 }; computing perPage from a difference (pageSize - skipped) that went negative.
Common situations: Config values read from env as negative numbers; 'show all' logic accidentally producing -1; division/subtraction bugs when deriving page size from remaining items.
Related errors
- perPage must be >= 0
- page must be >= 0
- page value too large
- Invalid knowledge node cursor.
- page must be >= 0
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/5fab7dd0b76157f4.
Report an issue: GitHub.