{"record":{"id":"2996e5ad34cbb013","repo":"mastra-ai/mastra","slug":"page-must-be-0-2996e5","errorCode":null,"errorMessage":"page must be >= 0","messagePattern":"page must be >= 0","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/mcp-servers/inmemory.ts","lineNumber":126,"sourceCode":"    return this.deepCopyConfig(updatedConfig);\n  }\n\n  async delete(id: string): Promise<void> {\n    // Idempotent delete\n    this.db.mcpServers.delete(id);\n    // Also delete all versions for this server\n    await this.deleteVersionsByParentId(id);\n  }\n\n  async list(args?: StorageListMCPServersInput): Promise<StorageListMCPServersOutput> {\n    const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status = 'published' } = 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 MCP servers and apply filters\n    let configs = Array.from(this.db.mcpServers.values());\n\n    // Filter by status\n    if (status) {\n      configs = configs.filter(config => config.status === status);\n    }\n\n    // Filter by authorId if provided\n    if (authorId !== undefined) {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/mcp-servers/inmemory.ts#L108-L144","documentation":"The in-memory MCP servers storage adapter validates pagination arguments in list(). A negative page index is rejected because page offsets cannot be below zero. This is an eager argument-validation guard so bad pagination input fails fast instead of producing an invalid slice.","triggerScenarios":"Calling the mcpServers domain list() (listMCPServers) with page < 0, e.g. page: -1, typically from an unvalidated API query parameter or a page counter decremented below zero.","commonSituations":"Server routes passing req.query.page directly without clamping; client-side 'load previous page' logic that goes below page 0; off-by-one in loop-driven pagination.","solutions":["Pass a page value >= 0 (first page is 0)","Clamp/validate page before calling, e.g. Math.max(0, Number(page) || 0)","Sanitize incoming query parameters with a schema (zod etc.) at the API boundary"],"exampleFix":"// before\nawait storage.listMCPServers({ page: -1 });\n// after\nconst page = Math.max(0, Number(input.page ?? 0));\nawait storage.listMCPServers({ page });","handlingStrategy":"validation","validationCode":"function assertPage(page: unknown): number {\n  const n = Number(page ?? 0);\n  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new RangeError(`page must be a non-negative integer, got ${page}`);\n  return n;\n}","typeGuard":"const isValidPage = (p: unknown): p is number => typeof p === 'number' && Number.isInteger(p) && p >= 0;","tryCatchPattern":"try {\n  return await storage.listMCPServers({ page });\n} catch (e) {\n  if (e instanceof Error && e.message === 'page must be >= 0') {\n    return storage.listMCPServers({ page: 0 });\n  }\n  throw e;\n}","preventionTips":["Validate page/perPage query params with zod at the API boundary","Remember page is 0-indexed in Mastra storage APIs","Clamp user-supplied page with Math.max(0, n) before any storage call"],"tags":["pagination","validation","storage"],"backgroundTag":"invalid-pagination-arguments","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}