{"record":{"id":"b81352b746dec1fb","repo":"mastra-ai/mastra","slug":"page-must-be-0-b81352","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/workspaces/inmemory.ts","lineNumber":203,"sourceCode":"    return this.deepCopyConfig(updatedConfig);\n  }\n\n  async delete(id: string): Promise<void> {\n    // Idempotent delete\n    this.db.workspaces.delete(id);\n    // Also delete all versions for this workspace\n    await this.deleteVersionsByParentId(id);\n  }\n\n  async list(args?: StorageListWorkspacesInput): Promise<StorageListWorkspacesOutput> {\n    const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = 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 workspaces and apply filters\n    let configs = Array.from(this.db.workspaces.values());\n\n    // Filter by authorId if provided\n    if (authorId !== undefined) {\n      configs = configs.filter(config => config.authorId === authorId);\n    }\n\n    // Filter by metadata if provided (AND logic)\n    if (metadata && Object.keys(metadata).length > 0) {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/workspaces/inmemory.ts#L185-L221","documentation":"Input validation in list(): the page argument must be a non-negative integer offset page index. Negative pages have no meaning for slice-based pagination, so the in-memory workspace domain rejects them explicitly instead of returning empty or wrapping around results.","triggerScenarios":"Calling storage.workspaces.list({ page: -1 }) or any negative number; passing an uninitialized/NaN-ish variable that ends up negative; off-by-one decrements when computing the previous page (page - 1 when page is already 0 minus more).","commonSituations":"Cursor/pagination UI state going negative when a user is on page 0 and clicks 'previous'; client-side code defaulting page to -1 to mean 'unset'; tests passing sentinel negative values.","solutions":["Clamp the computed page to 0 before calling list: Math.max(0, requestedPage)","If the caller means 'return everything', pass perPage: false instead of manipulating page","Fix pagination UI logic so 'previous' is disabled on page 0","Validate page inputs at API boundaries before forwarding to storage"],"exampleFix":"// before\nconst res = await storage.workspaces.list({ page: currentPage - 1 });\n// after\nconst page = Math.max(0, currentPage - 1);\nconst res = await storage.workspaces.list({ page });","handlingStrategy":"validation","validationCode":"function toSafePage(page: number): number {\n  if (!Number.isInteger(page) || page < 0) throw new RangeError(`page must be a non-negative integer, got ${page}`);\n  return page;\n}","typeGuard":"function isValidPage(page: unknown): page is number {\n  return typeof page === 'number' && Number.isInteger(page) && page >= 0;\n}","tryCatchPattern":"try {\n  return await storage.workspaces.list({ page, perPage });\n} catch (err) {\n  if (err instanceof Error && /page must be >= 0|page value too large/.test(err.message)) {\n    return { workspaces: [], total: 0, page: 0, perPage, hasMore: false };\n  }\n  throw err;\n}","preventionTips":["Clamp page with Math.max(0, page) at the data-access boundary","Disable 'previous' pagination controls at page 0","Sanitize/coerce external page params (query strings, API payloads)","Use perPage: false for fetch-all instead of extreme page tricks"],"tags":["pagination","validation","storage","workspace"],"backgroundTag":"invalid-pagination-params","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}