gastownhall/beads · error
pagination limit exceeded: stopped after %d pages
Error message
pagination limit exceeded: stopped after %d pages
What it means
SearchIssues aborts when pagination exceeds MaxPages iterations, returning nil results. The library enforces this as a runaway-loop guard so a JQL query whose pagination never terminates (or whose result set is enormous) cannot hang the caller forever. It is a deliberate safety limit, not a server error.
Source
Thrown at internal/jira/client.go:183
// SearchIssues queries Jira using JQL and returns all matching issues, handling pagination.
func (c *Client) SearchIssues(ctx context.Context, jql string) ([]Issue, error) {
var allIssues []Issue
startAt := 0
nextPageToken := ""
maxResults := 100
page := 0
useV2Pagination := c.APIVersion == "2"
for {
select {
case <-ctx.Done():
return allIssues, ctx.Err()
default:
}
page++
if page > MaxPages {
return nil, fmt.Errorf("pagination limit exceeded: stopped after %d pages", MaxPages)
}
params := url.Values{
"jql": {jql},
"fields": {searchFields},
"maxResults": {fmt.Sprintf("%d", maxResults)},
}
if useV2Pagination {
params.Set("startAt", fmt.Sprintf("%d", startAt))
} else if nextPageToken != "" {
params.Set("nextPageToken", nextPageToken)
}
// v3 uses /search/jql; v2 uses /search (both accept jql as a query param)
searchPath := "search/jql"
if useV2Pagination {
searchPath = "search"
}View on GitHub (pinned to 71377f2769)
Solutions
- Narrow the JQL: add time bounds (updated >= -7d), project, or component filters to reduce result count.
- Increase MaxPages if the limit is legitimately too low for your dataset.
- Check that c.APIVersion matches your deployment so the correct pagination mode (startAt vs nextPageToken) is used.
- Process results in batches with multiple targeted searches instead of one giant query.
Example fix
// before issues, err := client.SearchIssues(ctx, "project = BIGPROJECT") // after: bound the query window issues, err := client.SearchIssues(ctx, "project = BIGPROJECT AND updated >= -30d ORDER BY updated ASC")
Defensive patterns
Strategy: validation
Validate before calling
// Estimate result size before searching:
total, err := countIssues(client, jql) // run jql with maxResults=0 to read Total
if total > 5000 {
return fmt.Errorf("JQL matches %d issues; narrow the query or batch by time window", total)
} Type guard
func isPaginationLimit(err error) bool {
return err != nil && strings.Contains(err.Error(), "pagination limit exceeded")
} Try / catch
issues, err := client.SearchIssues(ctx, jql)
if isPaginationLimit(err) {
// fall back to time-sliced queries
for _, window := range timeWindows(30 * 24 * time.Hour) {
slice, e := client.SearchIssues(ctx, jql+" AND updated >= "+window[0]+" AND updated <= "+window[1])
if e != nil { return e }
issues = append(issues, slice...)
}
return nil
} Prevention
- Always scope JQL by project and a time window
- Check the search Total first with maxResults=0 before paginating fully
- Set MaxPages deliberately to match expected dataset size
- Keep APIVersion consistent with pagination semantics (v2 startAt vs v3 nextPageToken)
When it happens
Trigger: Calling SearchIssues with a JQL matching more issues than MaxPages * maxResults (100 per page), or a server whose pagination signal (Total / nextPageToken / isLast) never indicates completion.
Common situations: Overly broad JQL like project = X order by updated on a huge instance; a broken next-page token loop on Jira Cloud; API version mismatch (v2/v3 pagination semantics) causing the termination check never to fire.
Related errors
- search issues: %w
- parse Jira response: %w
- parse Jira timestamp: %w
- parse search response: %w
- get issue %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e4e901c1ef58cee3.
Report an issue: GitHub.