{"record":{"id":"79094bcf2f8bcfb9","repo":"mastra-ai/mastra","slug":"page-must-be-0-79094b","errorCode":null,"errorMessage":"page must be >= 0","messagePattern":"page must be >= 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/skills/inmemory.ts","lineNumber":229,"sourceCode":"    const {\n      page = 0,\n      perPage: perPageInput,\n      orderBy,\n      authorId,\n      status,\n      visibility,\n      metadata,\n      entityIds,\n      pinFavoritedFor,\n      favoritedOnly,\n    } = args || {};\n    const { field, direction } = this.parseOrderBy(orderBy);\n\n    // Normalize perPage for query (false → MAX_SAFE_INTEGER, 0 → 0, undefined → 100)\n    const perPage = normalizePerPage(perPageInput, 100);\n\n    if (page < 0) {\n      throw new Error('page must be >= 0');\n    }\n\n    // Prevent unreasonably large page values\n    const maxOffset = Number.MAX_SAFE_INTEGER / 2;\n    if (page * perPage > maxOffset) {\n      throw new Error('page value too large');\n    }\n\n    // Get all skills and apply filters\n    let configs = Array.from(this.db.skills.values());\n\n    // Restrict to a set of IDs (used by ?favoritedOnly=true).\n    // An empty array means \"no candidates\" -> empty result.\n    if (entityIds !== undefined) {\n      if (entityIds.length === 0) {\n        return {\n          skills: [],\n          total: 0,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/skills/inmemory.ts#L211-L247","documentation":"The in-memory skills list() validates that page is a non-negative integer-like value before computing offsets; negative pages are meaningless in this 0-indexed pagination scheme and are rejected with this error.","triggerScenarios":"Calling list(orderBy, -1, perPage) — e.g. a caller decrementing a 1-based page below 0, or propagating an unvalidated page from an HTTP query string (?page=-1).","commonSituations":"Off-by-one errors in pagination UI state; server handlers passing req.query.page straight through; defaulting logic that computes page = total - n producing negatives.","solutions":["Clamp: const safePage = Math.max(0, page) before calling list.","Validate incoming page parameters (schema validation, e.g. z.number().int().min(0)).","Convert 1-based client pages to 0-based with a guard for the first page.","Pass false as perPageInput if the intent was 'return everything' rather than navigating pages."],"exampleFix":"// before\nconst { skills } = await skillsStorage.list(orderBy, Number(req.query.page), 100);\n// after\nconst safePage = Math.max(0, parseInt(String(req.query.page ?? '0'), 10) || 0);\nconst { skills } = await skillsStorage.list(orderBy, safePage, 100);","handlingStrategy":"validation","validationCode":"function normalizePage(page: unknown): number {\n  const n = typeof page === 'number' ? page : parseInt(String(page ?? '0'), 10);\n  return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;\n}","typeGuard":"function isNonNegativeInt(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 0;\n}","tryCatchPattern":"try {\n  return await storage.list(orderBy, page, perPage);\n} catch (e) {\n  if (e instanceof Error && e.message === 'page must be >= 0') {\n    return storage.list(orderBy, 0, perPage);\n  }\n  throw e;\n}","preventionTips":["Clamp page at API boundaries before it reaches storage.","Parse and validate query-string pages (int, >= 0).","Convert 1-based UI pages with a guard against going below 0.","Centralize pagination normalization in a shared helper."],"tags":["storage","pagination","validation","in-memory"],"backgroundTag":"invalid-pagination-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}