{"record":{"id":"f0cf199f0352727b","repo":"jackwener/OpenCLI","slug":"twitter-followers-pagination-exceeded-max-pagina","errorCode":null,"errorMessage":"Twitter followers pagination exceeded ${MAX_PAGINATION_PAGES} pages before cursor exhaustion","messagePattern":"Twitter followers pagination exceeded (.+?) pages before cursor exhaustion","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/followers.js","lineNumber":194,"sourceCode":"        await consumeCaptured();\n        while (allFollowers.length < limit && cursor && pages < MAX_PAGINATION_PAGES) {\n            const beforeCount = allFollowers.length;\n            const beforeCursor = cursor;\n            await page.autoScroll({ times: 1, delayMs: 500 });\n            try {\n                await page.waitForCapture(CAPTURE_TIMEOUT_SECONDS);\n            }\n            catch {\n                throw new TimeoutError('twitter followers pagination', CAPTURE_TIMEOUT_SECONDS, `Twitter returned a continuation cursor after ${allFollowers.length} rows, but the next Followers response was not observed.`);\n            }\n            await consumeCaptured();\n            pages++;\n            if (allFollowers.length === beforeCount && cursor === beforeCursor) {\n                throw new CommandExecutionError('Twitter followers pagination repeated a cursor without returning new users');\n            }\n        }\n        if (allFollowers.length < limit && cursor && pages >= MAX_PAGINATION_PAGES) {\n            throw new CommandExecutionError(`Twitter followers pagination exceeded ${MAX_PAGINATION_PAGES} pages before cursor exhaustion`);\n        }\n        if (allFollowers.length === 0) {\n            if (looksLikePrivateTwitterTimeline(lastRawResponse)) {\n                throw new EmptyResultError('twitter followers', `No follower data returned for @${targetUser} (the target account may have set their followers list to private)`);\n            }\n            throw new EmptyResultError('twitter followers', `No followers found for @${targetUser}`);\n        }\n        return allFollowers.slice(0, limit);\n    }\n});\n\nexport const __test__ = {\n    extractFollower,\n    normalizeScreenName,\n    parseFollowers,\n    twitterGraphqlError,\n};\n","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/followers.js#L176-L212","documentation":"CommandExecutionError thrown when the twitter followers command exhausts MAX_PAGINATION_PAGES (100) scroll/capture rounds while the row count is still below --limit and a continuation cursor still exists. This guards against unbounded pagination when Twitter keeps issuing cursors but the command cannot converge on the requested number of rows.","triggerScenarios":"allFollowers.length < limit, a next cursor is still present, and pages >= 100 — i.e. the caller asked for more followers than 100 intercepted pages delivered (or progress was so slow the page cap hit first).","commonSituations":"Requesting --limit in the thousands (e.g. an account with millions of followers); very slow capture cycles causing each page to add few rows before the 100-page cap; X intermittently dropping pages so many rounds yield zero rows; aggressive rate limiting slowing delivery.","solutions":["Lower --limit to a value achievable within 100 pages (e.g. 200–500).","Re-run the command repeatedly and aggregate results externally if you genuinely need very large follower lists.","Ensure a fast, stable network so each captured page delivers a full batch of users.","Check whether X is rate-limiting the session; wait and retry with a fresh session."],"exampleFix":"// before\nopencli twitter followers @elonmusk --limit 100000\n// after\nopencli twitter followers @elonmusk --limit 500   # stay within the 100-page pagination budget","handlingStrategy":"validation","validationCode":"const MAX_ROWS_PER_100_PAGES = 2000; // heuristic budget\nif (limit > MAX_ROWS_PER_100_PAGES) {\n  throw new Error(`--limit ${limit} likely exceeds the 100-page pagination budget; use <= ${MAX_ROWS_PER_100_PAGES} or paginate manually`);\n}","typeGuard":"function isAchievableLimit(limit) { return Number.isInteger(limit) && limit > 0 && limit <= 2000; }","tryCatchPattern":"try {\n  rows = await opencli.twitter.followers(user, { limit });\n} catch (e) {\n  if (String(e.message).includes('exceeded') && String(e.message).includes('pages')) {\n    // fall back to a lower limit\n    rows = await opencli.twitter.followers(user, { limit: 500 });\n  } else throw e;\n}","preventionTips":["Request realistic limits (hundreds, not tens of thousands)","Aggregate multiple smaller runs if you need very large lists","Keep pages progressing quickly (good network, focused tab)","Monitor partial progress and persist incrementally"],"tags":["pagination","limit","rate-limiting","twitter"],"backgroundTag":"pagination-limit-exceeded","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}