{"record":{"id":"54702729cf43bd63","repo":"koala73/worldmonitor","slug":"sentry-issues-pagination-exceeded-max-pages-pages","errorCode":null,"errorMessage":"Sentry issues pagination exceeded ${MAX_PAGES} pages","messagePattern":"Sentry issues pagination exceeded (.+?) pages","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/audit-sentry-resolve-pins.mjs","lineNumber":251,"sourceCode":"          + '(or SENTRY_SESSION_TOKEN) and rerun.',\n      );\n    }\n    if (!response.ok) {\n      throw new Error(`Sentry issues request failed: HTTP ${response.status} ${response.statusText}`);\n    }\n    const batch = await response.json();\n    if (!Array.isArray(batch)) throw new Error('Sentry issues response was not an array');\n    issues.push(...batch);\n\n    const { next } = parseLinkHeader(response.headers.get('link'));\n    if (!next) {\n      assertLiveBoardIsNotEmpty(issues, org, project);\n      return issues;\n    }\n    url = sameOriginCursor(next);\n  }\n\n  throw new Error(`Sentry issues pagination exceeded ${MAX_PAGES} pages`);\n}\n\nasync function main() {\n  const args = parseArguments(process.argv.slice(2));\n  const org = process.env.SENTRY_ORG || DEFAULT_ORG;\n  const project = process.env.SENTRY_PROJECT || DEFAULT_PROJECT;\n\n  let issues;\n  if (args.input) {\n    issues = JSON.parse(readFileSync(args.input, 'utf8'));\n  } else {\n    const token = process.env.SENTRY_SESSION_TOKEN || process.env.SENTRY_AUTH_TOKEN;\n    if (!token) {\n      throw new Error(\n        'Set SENTRY_AUTH_TOKEN (or SENTRY_SESSION_TOKEN) to a `sntryu_` user token with '\n          + '`event:read` and `project:read`, or pass --input <path> to audit a saved payload.',\n      );\n    }","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/audit-sentry-resolve-pins.mjs#L233-L269","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (scripts/audit-sentry-resolve-pins.mjs:62)\nconst MAX_PAGES = 50;\n// after\nconst MAX_PAGES = 200;","handlingStrategy":"validation","validationCode":"// sanity-check the page size needed before paginating\nconst PAGE_SIZE = 100;\nconst estimated = await fetch(`${SENTRY_HOST}/api/0/projects/${org}/${project}/issues/?query=is:resolved&limit=1`, { headers: { Authorization: `Bearer ${token}` } });\n// If Link headers suggest more than MAX_PAGES * PAGE_SIZE issues, narrow the query first.\nif (MAX_PAGES * PAGE_SIZE < 5000) throw new Error('Query too broad; narrow statsPeriod or raise MAX_PAGES');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["sentry","pagination","api","loop"],"backgroundTag":"unexpected-response-shape","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}