{"record":{"id":"66012759ffa508a0","repo":"Budibase/budibase","slug":"bookmark-query-exceeds-maximum-scan-window-of-ma","errorCode":null,"errorMessage":"Bookmark query exceeds maximum scan window of ${MAX_SESSION_SCAN_LIMIT} sessions","messagePattern":"Bookmark query exceeds maximum scan window of (.+?) sessions","errorType":"validation","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/agentLogs/shared.ts","lineNumber":215,"sourceCode":"  if (!Number.isFinite(parsedBookmark) || parsedBookmark < 1) {\n    throw new HTTPError(\"Invalid bookmark query\", 400)\n  }\n\n  return parsedBookmark\n}\n\nexport function normalizeSessionLimit(limit?: number): number {\n  if (!limit || limit <= 0) {\n    return DEFAULT_SESSION_PAGE_SIZE\n  }\n\n  return Math.min(limit, MAX_SESSION_PAGE_SIZE)\n}\n\nexport function getMergedSessionLimit(page: number, pageSize: number): number {\n  const mergedLimit = (page - 1) * pageSize + pageSize + 1\n  if (mergedLimit > MAX_SESSION_SCAN_LIMIT) {\n    throw new HTTPError(\n      `Bookmark query exceeds maximum scan window of ${MAX_SESSION_SCAN_LIMIT} sessions`,\n      400\n    )\n  }\n\n  return mergedLimit\n}\n\nexport function mapRequestModel(data: LiteLLMRequestDetail) {\n  return (\n    data.response?.model || data.model || data.proxy_server_request?.model || \"\"\n  )\n}\n\nfunction getDateBoundary(\n  value: string,\n  mode: \"start\" | \"end\"\n): Date | undefined {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/agentLogs/shared.ts#L197-L233","documentation":"getMergedSessionLimit converts a bookmark page number and page size into a single scan limit for paginating agent log sessions. The computed limit is (page-1)*pageSize + pageSize + 1 (pages plus one lookahead row). If that value exceeds MAX_SESSION_SCAN_LIMIT (5000), the server refuses to run the query because it would have to scan too many sessions, and throws HTTPError with status 400.","triggerScenarios":"Calling the agent log sessions/bookmark listing endpoint with a page number whose (page-1)*pageSize + pageSize + 1 exceeds 5000 — e.g. page=51 with pageSize=100, or page=63 with pageSize=75.","commonSituations":"A client UI deep-links to or retries with a very large bookmark page; a pagination loop that keeps advancing the page instead of using cursors; a caller passing an unvalidated page parameter from a URL query string.","solutions":["Use a lower page number so (page-1)*pageSize + pageSize + 1 stays at or below 5000","Reduce pageSize to allow more pages within the 5000-session scan window","Filter or narrow the query (dates, agent) so the requested page falls within the window instead of paging that deep","For deep pagination, switch to a cursor/bookmark-key approach rather than numeric page offset"],"exampleFix":"// before\nconst limit = getMergedSessionLimit(page, pageSize) // throws at page=51, pageSize=100\n// after\nconst MAX_SESSION_SCAN_LIMIT = 5000\nconst safePage = Math.min(page, Math.floor(MAX_SESSION_SCAN_LIMIT / pageSize))\nconst limit = getMergedSessionLimit(safePage, pageSize)","handlingStrategy":"validation","validationCode":"const MAX_SESSION_SCAN_LIMIT = 5000\nexport function isSafeSessionPage(page: number, pageSize: number): boolean {\n  return (page - 1) * pageSize + pageSize + 1 <= MAX_SESSION_SCAN_LIMIT\n}\nif (!isSafeSessionPage(page, pageSize)) {\n  // clamp page or surface a friendlier message before calling the API\n  page = Math.max(1, Math.floor(MAX_SESSION_SCAN_LIMIT / pageSize))\n}","typeGuard":null,"tryCatchPattern":"try {\n  const sessions = await fetchAgentLogSessions({ page, pageSize })\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400 && /scan window/.test(err.message)) {\n    // clamp the page and retry from page 1\n  }\n}","preventionTips":["Clamp the requested page to Math.floor(5000/pageSize) before each pagination step","Use cursor-based pagination instead of ever-growing page offsets","Validate page/pageSize are positive integers before calling the API"],"tags":["pagination","http-400","input-validation","agent-logs"],"backgroundTag":"pagination-limit-exceeded","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}