Budibase/budibase · warning · HTTPError

Invalid bookmark query

Error message

Invalid bookmark query

What it means

parseBookmarkPage validates the pagination bookmark query parameter and throws HTTPError 400 'Invalid bookmark query' when the bookmark is non-numeric. It backs the 'page' resolver, so this surfaces directly to API callers of the agent-log session endpoints.

Source

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

  return firstDate >= secondDate
    ? firstDate.toISOString()
    : secondDate.toISOString()
}

export function truncateText(value: string, maxLength = 100): string {
  if (value.length <= maxLength) {
    return value
  }
  return `${value.slice(0, maxLength)}...`
}

export function parseBookmarkPage(bookmark?: string): number {
  if (!bookmark) {
    return DEFAULT_BOOKMARK_PAGE
  }
  if (!/^\d+$/.test(bookmark)) {
    throw new HTTPError("Invalid bookmark query", 400)
  }

  const parsedBookmark = Number.parseInt(bookmark, 10)
  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)
}

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Send a positive integer as the bookmark query param, e.g. ?bookmark=2
  2. Validate the bookmark is /^\d+$/ in the client before calling the API, else omit it for page 1
  3. Regenerate the bookmark from the API response's nextBookmark instead of hand-crafting it
  4. Check for client/server pagination scheme mismatch after an API version upgrade

Example fix

// before
const url = `/api/agent/logs?bookmark=${cursorToken}`
// after
const page = Number.parseInt(cursorToken, 10)
const qs = Number.isInteger(page) && page > 0 ? `?bookmark=${page}` : ""
const url = `/api/agent/logs${qs}`
Defensive patterns

Strategy: validation

Validate before calling

function isValidBookmark(b: unknown): b is string {
  return typeof b === "string" && /^\d+$/.test(b)
}

Try / catch

try {
  const res = await api.get("/agent/sessions", { bookmark })
} catch (err) {
  if (err instanceof HTTPError && err.status === 400) {
    return api.get("/agent/sessions") // reset to page 1
  }
  throw err
}

Prevention

When it happens

Trigger: GET agent session endpoints with ?bookmark=abc, ?bookmark=1.5, ?bookmark=%20, or any value failing /^\d+$/ — e.g. a client passing an opaque cursor string where a numeric page number is expected.

Common situations: Frontend reuses a cursor-style bookmark from another paginated API; URL encodes whitespace into the bookmark; bookmarks persisted as floats or strings with leading '+'; stale client code after the pagination scheme changed from cursors to page numbers.

Related errors


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