Budibase/budibase · error · HTTPError

Bookmark query exceeds maximum scan window of ${MAX_SESSION_

Error message

Bookmark query exceeds maximum scan window of ${MAX_SESSION_SCAN_LIMIT} sessions

What it means

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.

Source

Thrown at packages/server/src/sdk/workspace/ai/agentLogs/shared.ts:215

  if (!Number.isFinite(parsedBookmark) || parsedBookmark < 1) {
    throw new HTTPError("Invalid bookmark query", 400)
  }

  return parsedBookmark
}

export function normalizeSessionLimit(limit?: number): number {
  if (!limit || limit <= 0) {
    return DEFAULT_SESSION_PAGE_SIZE
  }

  return Math.min(limit, MAX_SESSION_PAGE_SIZE)
}

export function getMergedSessionLimit(page: number, pageSize: number): number {
  const mergedLimit = (page - 1) * pageSize + pageSize + 1
  if (mergedLimit > MAX_SESSION_SCAN_LIMIT) {
    throw new HTTPError(
      `Bookmark query exceeds maximum scan window of ${MAX_SESSION_SCAN_LIMIT} sessions`,
      400
    )
  }

  return mergedLimit
}

export function mapRequestModel(data: LiteLLMRequestDetail) {
  return (
    data.response?.model || data.model || data.proxy_server_request?.model || ""
  )
}

function getDateBoundary(
  value: string,
  mode: "start" | "end"
): Date | undefined {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Use a lower page number so (page-1)*pageSize + pageSize + 1 stays at or below 5000
  2. Reduce pageSize to allow more pages within the 5000-session scan window
  3. Filter or narrow the query (dates, agent) so the requested page falls within the window instead of paging that deep
  4. For deep pagination, switch to a cursor/bookmark-key approach rather than numeric page offset

Example fix

// before
const limit = getMergedSessionLimit(page, pageSize) // throws at page=51, pageSize=100
// after
const MAX_SESSION_SCAN_LIMIT = 5000
const safePage = Math.min(page, Math.floor(MAX_SESSION_SCAN_LIMIT / pageSize))
const limit = getMergedSessionLimit(safePage, pageSize)
Defensive patterns

Strategy: validation

Validate before calling

const MAX_SESSION_SCAN_LIMIT = 5000
export function isSafeSessionPage(page: number, pageSize: number): boolean {
  return (page - 1) * pageSize + pageSize + 1 <= MAX_SESSION_SCAN_LIMIT
}
if (!isSafeSessionPage(page, pageSize)) {
  // clamp page or surface a friendlier message before calling the API
  page = Math.max(1, Math.floor(MAX_SESSION_SCAN_LIMIT / pageSize))
}

Try / catch

try {
  const sessions = await fetchAgentLogSessions({ page, pageSize })
} catch (err) {
  if (err instanceof HTTPError && err.status === 400 && /scan window/.test(err.message)) {
    // clamp the page and retry from page 1
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/66012759ffa508a0. Report an issue: GitHub.