jackwener/OpenCLI · error · CommandExecutionError
Twitter followers pagination repeated a cursor without retur
Error message
Twitter followers pagination repeated a cursor without returning new users
What it means
CommandExecutionError thrown when a pagination round of the twitter followers command produces no progress: the follower row count and the continuation cursor are identical to the values captured before the scroll. This means Twitter is serving the same cursor back without new users, so looping further would never finish. The library aborts instead of spinning forever.
Source
Thrown at clis/twitter/followers.js:190
cursor = nextCursor;
}
};
await consumeCaptured();
while (allFollowers.length < limit && cursor && pages < MAX_PAGINATION_PAGES) {
const beforeCount = allFollowers.length;
const beforeCursor = cursor;
await page.autoScroll({ times: 1, delayMs: 500 });
try {
await page.waitForCapture(CAPTURE_TIMEOUT_SECONDS);
}
catch {
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.`);
}
await consumeCaptured();
pages++;
if (allFollowers.length === beforeCount && cursor === beforeCursor) {
throw new CommandExecutionError('Twitter followers pagination repeated a cursor without returning new users');
}
}
if (allFollowers.length < limit && cursor && pages >= MAX_PAGINATION_PAGES) {
throw new CommandExecutionError(`Twitter followers pagination exceeded ${MAX_PAGINATION_PAGES} pages before cursor exhaustion`);
}
if (allFollowers.length === 0) {
if (looksLikePrivateTwitterTimeline(lastRawResponse)) {
throw new EmptyResultError('twitter followers', `No follower data returned for @${targetUser} (the target account may have set their followers list to private)`);
}
throw new EmptyResultError('twitter followers', `No followers found for @${targetUser}`);
}
return allFollowers.slice(0, limit);
}
});
export const __test__ = {
extractFollower,
normalizeScreenName,View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command; duplicated cursor responses are frequently transient on X's side.
- Log out/in or refresh ct0/auth_token cookies so X serves fresh timeline data.
- Lower --limit so the command finishes before reaching the degenerate page.
- Report/pin the account behavior — if it persists only for one target account, the account's follower timeline is likely restricted.
Example fix
// before opencli twitter followers @restrictedaccount --limit 500 // after opencli twitter followers @restrictedaccount --limit 100 # stop before the degenerate repeated-cursor page
Defensive patterns
Strategy: retry
Validate before calling
// No pre-call validation can detect server-side cursor loops; ensure a healthy logged-in session first:
const cookies = await page.getCookies({ url: 'https://x.com' });
if (!cookies.some(c => c.name === 'ct0')) throw new Error('Log into x.com before scraping'); Try / catch
try {
rows = await opencli.twitter.followers(user, { limit });
} catch (e) {
if (String(e.message).includes('repeated a cursor')) {
rows = await opencli.twitter.followers(user, { limit: Math.min(limit, 100) }); // fresh session retry
} else throw e;
} Prevention
- Refresh your x.com session if duplicate-cursor errors recur
- Cap --limit below the point where X starts replaying pages
- Treat persistent repeats for one account as an account restriction
- Report recurring loops as a possible X payload regression
When it happens
Trigger: After consumeCaptured() of the next Followers response, allFollowers.length === beforeCount AND cursor === beforeCursor — Twitter returned a page whose only cursor is the same value already consumed and zero new user- entries.
Common situations: X GraphQL endpoint serving cached/duplicated timeline pages (server-side bug or A/B variant); a private/limited followers list where the API echoes the final cursor endlessly; stale session cookies making X replay the last good page; scraping an account whose followers were recently frozen.
Related errors
- twitter_bookmarks_repeated_cursor
- twitter_bookmarks_archive_incomplete
- twitter_collection_invalid_timestamp
- twitter_collection_limit_reached
- twitter_collection_repeated_cursor
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6fe7509646627b51.
Report an issue: GitHub.