koala73/worldmonitor · error · Error
Sentry issues pagination exceeded ${MAX_PAGES} pages
Error message
Sentry issues pagination exceeded ${MAX_PAGES} pages What it means
fetchResolvedIssues() follows the `Link` header cursor returned by Sentry, but caps the loop at MAX_PAGES = 50 to protect against runaway pagination. If 50 pages still yield a `next` cursor, the loop exits and this error is thrown, treating unbounded pagination as a malfunction rather than iterating forever.
Solutions
- Inspect the cursors being followed — if the same cursor repeats, a proxy or cache is interfering; bypass it or fix SENTRY_HOST.
- Narrow the query by exporting a smaller statsPeriod or adjusting the `query` param in issuesUrl() if the org genuinely has >50 pages.
- Save an intermediate payload and audit offline with `--input` instead of paginating live.
- If legitimate, raise MAX_PAGES in scripts/audit-sentry-resolve-pins.mjs:62.
Example fix
// before (scripts/audit-sentry-resolve-pins.mjs:62) const MAX_PAGES = 50; // after const MAX_PAGES = 200;
Defensive patterns
Strategy: validation
Validate before calling
// sanity-check the page size needed before paginating
const PAGE_SIZE = 100;
const estimated = await fetch(`${SENTRY_HOST}/api/0/projects/${org}/${project}/issues/?query=is:resolved&limit=1`, { headers: { Authorization: `Bearer ${token}` } });
// If Link headers suggest more than MAX_PAGES * PAGE_SIZE issues, narrow the query first.
if (MAX_PAGES * PAGE_SIZE < 5000) throw new Error('Query too broad; narrow statsPeriod or raise MAX_PAGES'); Prevention
- Narrow the `query`/`statsPeriod` in issuesUrl() when the org has very large resolved-issue counts.
- Log each cursor URL during debugging to detect non-advancing (looping) cursors early.
- Bypass intermediary caches/proxies that could serve the same page repeatedly.
- Only raise MAX_PAGES after confirming the pagination is genuinely long, not stuck.
When it happens
Trigger: 50 consecutive pages of the issues endpoint each return a `Link: rel="next"` cursor — e.g. a misbehaving cursor loop (same cursor repeated), a proxy stripping the query so the filter never applies, or a genuinely huge resolved-issue count with PAGE_SIZE pages exceeding 50.
Common situations: A gateway caching or rewriting responses so the cursor never advances; a bogus/self-hosted endpoint echoing the same Link header; unusually large org where `is:resolved` with an empty statsPeriod spans thousands of issues.
Related errors
- ECCC_PAGE_LIMIT
- ECCC_AGGREGATE_TOO_LARGE
- Expected an array of Sentry issues. A Sentry error body is a
- Sentry pagination cursor left ${SENTRY_HOST}: ${new URL(next
- Sentry issues request failed: HTTP ${response.status} ${resp
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/54702729cf43bd63.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/audit-sentry-resolve-pins.mjs:251
+ '(or SENTRY_SESSION_TOKEN) and rerun.',
);
}
if (!response.ok) {
throw new Error(`Sentry issues request failed: HTTP ${response.status} ${response.statusText}`);
}
const batch = await response.json();
if (!Array.isArray(batch)) throw new Error('Sentry issues response was not an array');
issues.push(...batch);
const { next } = parseLinkHeader(response.headers.get('link'));
if (!next) {
assertLiveBoardIsNotEmpty(issues, org, project);
return issues;
}
url = sameOriginCursor(next);
}
throw new Error(`Sentry issues pagination exceeded ${MAX_PAGES} pages`);
}
async function main() {
const args = parseArguments(process.argv.slice(2));
const org = process.env.SENTRY_ORG || DEFAULT_ORG;
const project = process.env.SENTRY_PROJECT || DEFAULT_PROJECT;
let issues;
if (args.input) {
issues = JSON.parse(readFileSync(args.input, 'utf8'));
} else {
const token = process.env.SENTRY_SESSION_TOKEN || process.env.SENTRY_AUTH_TOKEN;
if (!token) {
throw new Error(
'Set SENTRY_AUTH_TOKEN (or SENTRY_SESSION_TOKEN) to a `sntryu_` user token with '
+ '`event:read` and `project:read`, or pass --input <path> to audit a saved payload.',
);
}View on GitHub (pinned to 7d06c8633d)