{"record":{"id":"8b4619b3fdeb12d7","repo":"gastownhall/beads","slug":"pagination-limit-exceeded-stopped-after-d-pages","errorCode":null,"errorMessage":"pagination limit exceeded: stopped after %d pages","messagePattern":"pagination limit exceeded: stopped after (.+?) pages","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":273,"sourceCode":"\t\t}\n\n\t\tvar issues []Issue\n\t\tif err := json.Unmarshal(respBody, &issues); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse issues response: %w\", err)\n\t\t}\n\n\t\tallIssues = append(allIssues, issues...)\n\n\t\t// Check for next page\n\t\tnextPage := headers.Get(\"X-Next-Page\")\n\t\tif nextPage == \"\" {\n\t\t\tbreak\n\t\t}\n\t\tpage++\n\n\t\t// Guard against infinite pagination loops from malformed responses\n\t\tif page > MaxPages {\n\t\t\treturn nil, fmt.Errorf(\"pagination limit exceeded: stopped after %d pages\", MaxPages)\n\t\t}\n\t}\n\n\treturn filterByProject(allIssues, filter), nil\n}\n\n// FetchIssuesSince retrieves issues from GitLab that have been updated since the given time.\n// This enables incremental sync by only fetching issues modified after the last sync.\nfunc (c *Client) FetchIssuesSince(ctx context.Context, state string, since time.Time, filters ...*IssueFilter) ([]Issue, error) {\n\tvar filter *IssueFilter\n\tif len(filters) > 0 {\n\t\tfilter = filters[0]\n\t}\n\n\tvar allIssues []Issue\n\tpage := 1\n\n\tsinceStr := since.UTC().Format(time.RFC3339)","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L255-L291","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nclient := gitlab.NewClient(token, gitlab.WithMaxPages(10)) // too small for huge project\n// after\nclient := gitlab.NewClient(token, gitlab.WithMaxPages(100)) // or use FetchIssuesSince","handlingStrategy":"validation","validationCode":"resp, _ := http.Get(baseURL + \"/api/v4/projects/\" + proj + \"/issues?per_page=100\")\ntotal := resp.Header.Get(\"X-Total-Pages\")\nn, _ := strconv.Atoi(total)\nif n > maxPagesConfigured { return fmt.Errorf(\"project needs %d pages > MaxPages %d\", n, maxPagesConfigured) }","typeGuard":"func isPaginationLimitErr(err error) bool {\n\treturn strings.Contains(err.Error(), \"pagination limit exceeded\")\n}","tryCatchPattern":"issues, err := client.FetchIssues(ctx, \"opened\")\nif err != nil {\n\tif strings.Contains(err.Error(), \"pagination limit exceeded\") {\n\t\t// switch to incremental sync or raise MaxPages\n\t}\n}","preventionTips":["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"],"tags":["gitlab","pagination","network"],"backgroundTag":"pagination-limit-exceeded","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}