mastra-ai/mastra · error

page must be >= 0

Error message

page must be >= 0

What it means

`listWorkflowRuns` validates that `page`, when provided, is non-negative, throwing 'page must be >= 0'. Pages are zero-indexed; negative values indicate caller-side pagination bugs. Thrown before any filtering of runs occurs.

Source

Thrown at packages/core/src/storage/domains/workflows/inmemory.ts:347

      return null;
    }

    const snapshot = typeof run.snapshot === 'string' ? JSON.parse(run.snapshot) : run.snapshot;
    // Return a deep copy to prevent mutation
    return snapshot ? cloneRunData(snapshot) : null;
  }

  async listWorkflowRuns({
    workflowName,
    fromDate,
    toDate,
    perPage,
    page,
    resourceId,
    status,
  }: StorageListWorkflowRunsInput = {}): Promise<WorkflowRuns> {
    if (page !== undefined && page < 0) {
      throw new Error('page must be >= 0');
    }

    let runs = Array.from(this.db.workflows.values());

    if (workflowName) runs = runs.filter((run: any) => run.workflow_name === workflowName);
    if (status) {
      runs = runs.filter((run: any) => {
        let snapshot: WorkflowRunState | string = run?.snapshot!;

        if (!snapshot) {
          return false;
        }

        if (typeof snapshot === 'string') {
          try {
            snapshot = JSON.parse(snapshot) as WorkflowRunState;
          } catch {
            return false;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Clamp with `Math.max(0, page)` before calling.
  2. Fix prev-page logic to stop at 0.
  3. To fetch all runs, omit `page`/`perPage` or pass a large perPage instead of a negative page.
  4. Validate pagination query params at the API boundary.

Example fix

// before
await storage.listWorkflowRuns({ page: pageNum - 1 }); // pageNum could be 0
// after
await storage.listWorkflowRuns({ page: Math.max(0, pageNum - 1) });
Defensive patterns

Strategy: validation

Validate before calling

function toPage(page: unknown): number | undefined {
  if (page === undefined) return undefined;
  const n = typeof page === 'number' ? page : parseInt(String(page), 10);
  return Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : undefined;
}
// usage
await storage.listWorkflowRuns({ page: toPage(rawPage) });

Type guard

function isValidPage(page: unknown): page is number {
  return typeof page === 'number' && Number.isInteger(page) && page >= 0;
}

Try / catch

try {
  return await storage.listWorkflowRuns({ page });
} catch (err) {
  if (err instanceof Error && err.message === 'page must be >= 0') {
    return storage.listWorkflowRuns({ page: 0 });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `listWorkflowRuns({ page: -1 })` or passing a page derived from `pageIndex - 1` when already at 0, or unvalidated negative user input flowing into the query.

Common situations: 'Previous page' UI logic going below zero, negative sentinel values used to mean 'all runs', or arithmetic underflow in offset-to-page conversions.

Related errors


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