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
- Send a positive integer as the bookmark query param, e.g. ?bookmark=2
- Validate the bookmark is /^\d+$/ in the client before calling the API, else omit it for page 1
- Regenerate the bookmark from the API response's nextBookmark instead of hand-crafting it
- 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
- Only pass numeric page bookmarks; omit for page 1
- Use the nextBookmark returned by the API
- Reject cursor-style tokens before sending
- Clamp values with /^\d+$/ client-side
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
- Invalid bookmark query
- Invalid limit query
- Limit query must be between 1 and 100
- Invalid limit query
- Limit query must be between 1 and 100
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/ace9676557333fea.
Report an issue: GitHub.