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

  1. Clamp the value before the call: perPage: Math.max(0, desiredPerPage).
  2. If 'all results' was intended, omit perPage or pass undefined (library applies its default / MAX_SAFE_INTEGER path) rather than a huge/negative number.
  3. Guard computed values — if a subtraction can go negative, fall back to 0 or undefined.
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/2486fc25e7658526. Report an issue: GitHub.