{"record":{"id":"928bbe2abff7d225","repo":"mastra-ai/mastra","slug":"page-must-be-0-928bbe","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/scorer-definitions/inmemory.ts","lineNumber":144,"sourceCode":"\n  async list(args?: StorageListScorerDefinitionsInput): Promise<StorageListScorerDefinitionsOutput> {\n    const {\n      page = 0,\n      perPage: perPageInput,\n      orderBy,\n      authorId,\n      organizationId,\n      projectId,\n      metadata,\n      status,\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 scorer definitions and apply filters\n    let scorers = Array.from(this.db.scorerDefinitions.values());\n\n    // Filter by status\n    if (status) {\n      scorers = scorers.filter(scorer => scorer.status === status);\n    }\n\n    // Filter by authorId if provided\n    if (authorId !== undefined) {","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/scorer-definitions/inmemory.ts#L126-L162","documentation":"The in-memory scorer-definitions list() validates that page is non-negative before paginating. Negative pages are meaningless in offset pagination, so the method throws right after normalizing perPage (false -> MAX_SAFE_INTEGER, 0 -> 0, undefined -> 100).","triggerScenarios":"Calling storage.scorerDefinitions.list({ page: -1 }); passing a computed page like currentIndex - 1 that goes below zero; forwarding an unvalidated negative query param.","commonSituations":"Off-by-one errors in 'previous page' UI logic; sentinel values of -1 for 'unset'; parsing page from URLs/JSON without clamping.","solutions":["Clamp before calling: Math.max(0, page).","Default page to 0 when the value is absent or a sentinel like -1.","Use perPage: false (page 0) to list all scorer definitions instead of paging.","Validate numeric inputs at the boundary (API handlers, CLI args) before passing them on."],"exampleFix":"// before\nawait storage.scorerDefinitions.list({ page: prevPage - 1 });\n// after\nawait storage.scorerDefinitions.list({ page: Math.max(0, prevPage - 1) });","handlingStrategy":"validation","validationCode":"function coercePage(p: number | undefined): number {\n  const n = p ?? 0;\n  if (!Number.isInteger(n) || n < 0) return 0;\n  return n;\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.scorerDefinitions.list({ page });\n} catch (e) {\n  if (e instanceof Error && e.message === 'page must be >= 0') {\n    return storage.scorerDefinitions.list({ page: 0 });\n  }\n  throw e;\n}","preventionTips":["Clamp page at every call site: Math.max(0, page).","Replace -1 sentinels with undefined so the default (page 0) applies.","Validate page inputs at API/CLI boundaries.","Unit-test pagination helpers for the zero/first-page boundary."],"tags":["storage","pagination","argument-validation","scorer-definitions"],"backgroundTag":"invalid-page-number","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}