gastownhall/beads · error
pagination limit exceeded: stopped after %d pages
Error message
pagination limit exceeded: stopped after %d pages
What it means
FetchIssues paginated more than MaxPages pages and the X-Next-Page header kept appearing, so the library stops and returns this error to avoid an infinite loop. It indicates a malformed pagination response or an implausibly large result set.
Source
Thrown at internal/gitlab/client.go:273
}
var issues []Issue
if err := json.Unmarshal(respBody, &issues); err != nil {
return nil, fmt.Errorf("failed to parse issues response: %w", err)
}
allIssues = append(allIssues, issues...)
// Check for next page
nextPage := headers.Get("X-Next-Page")
if nextPage == "" {
break
}
page++
// Guard against infinite pagination loops from malformed responses
if page > MaxPages {
return nil, fmt.Errorf("pagination limit exceeded: stopped after %d pages", MaxPages)
}
}
return filterByProject(allIssues, filter), nil
}
// FetchIssuesSince retrieves issues from GitLab that have been updated since the given time.
// This enables incremental sync by only fetching issues modified after the last sync.
func (c *Client) FetchIssuesSince(ctx context.Context, state string, since time.Time, filters ...*IssueFilter) ([]Issue, error) {
var filter *IssueFilter
if len(filters) > 0 {
filter = filters[0]
}
var allIssues []Issue
page := 1
sinceStr := since.UTC().Format(time.RFC3339)View on GitHub (pinned to 71377f2769)
Solutions
- Verify the server honors per_page by checking X-Total-Pages/X-Next-Page on a manual curl
- Check whether a proxy or mock is replaying the X-Next-Page header
- Increase MaxPages in the library if the project legitimately exceeds it
- Use FetchIssuesSince for incremental sync to reduce pages fetched
Example fix
// before client := gitlab.NewClient(token, gitlab.WithMaxPages(10)) // too small for huge project // after client := gitlab.NewClient(token, gitlab.WithMaxPages(100)) // or use FetchIssuesSince
Defensive patterns
Strategy: validation
Validate before calling
resp, _ := http.Get(baseURL + "/api/v4/projects/" + proj + "/issues?per_page=100")
total := resp.Header.Get("X-Total-Pages")
n, _ := strconv.Atoi(total)
if n > maxPagesConfigured { return fmt.Errorf("project needs %d pages > MaxPages %d", n, maxPagesConfigured) } Type guard
func isPaginationLimitErr(err error) bool {
return strings.Contains(err.Error(), "pagination limit exceeded")
} Try / catch
issues, err := client.FetchIssues(ctx, "opened")
if err != nil {
if strings.Contains(err.Error(), "pagination limit exceeded") {
// switch to incremental sync or raise MaxPages
}
} Prevention
- Use FetchIssuesSince for large projects instead of full scans
- Verify the environment honors per_page (no proxies stripping query params)
- Set MaxPages above X-Total-Pages for your largest project
- Be careful with mock servers: always terminate X-Next-Page correctly in tests
When it happens
Trigger: The GitLab API (or an interceptor) keeps returning a non-empty X-Next-Page header for more than MaxPages consecutive pages during FetchIssues, e.g. a proxy replaying headers or per_page being ignored.
Common situations: Corporate proxies stripping per_page or echoing X-Next-Page, mocking servers that always set X-Next-Page, or extremely large projects exceeding MaxPages with a small MaxPageSize.
Related errors
- request failed (attempt %d/%d): %w
- failed to read response (attempt %d/%d): %w
- max retries (%d) exceeded: %w
- failed to fetch issues: %w
- failed to parse issues response: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8b4619b3fdeb12d7.
Report an issue: GitHub.