jackwener/OpenCLI · error · CommandExecutionError
twitter_collection_repeated_cursor
twitter_collection_repeated_cursor
Error message
twitter_collection_repeated_cursor: pagination cannot prove completion
What it means
paginateCollection tracks every cursor it has seen; if the next cursor equals the current one or was already visited, X is serving a pagination loop. Since a loop means the run could cycle forever without proving it reached 'until', the library throws this error immediately.
Source
Thrown at clis/twitter/collection.js:289
}
const createdAt = parseCreatedAt(post);
if (!oldestSeenAt || createdAt < oldestSeenAt) oldestSeenAt = createdAt;
posts.push(post);
if (createdAt <= until) {
return {
posts,
receipt: completedReceipt('time_boundary_reached', until, pageIndex + 1, oldestSeenAt),
};
}
}
if (!nextCursor) {
return {
posts,
receipt: completedReceipt('cursor_exhausted', until, pageIndex + 1, oldestSeenAt),
};
}
if (nextCursor === cursor || seenCursors.has(nextCursor)) {
throw new CommandExecutionError('twitter_collection_repeated_cursor: pagination cannot prove completion');
}
if (posts.length >= limit) {
throw new CommandExecutionError('twitter_collection_limit_reached: pagination cannot prove completion');
}
seenCursors.add(nextCursor);
cursor = nextCursor;
}
throw new CommandExecutionError('twitter_collection_page_guard_hit: pagination cannot prove completion');
}
cli({
site: 'twitter',
name: 'collection',
access: 'read',
description: 'Fetch a user timeline with relationship facts and a bounded completion receipt.',
domain: 'x.com',
strategy: Strategy.COOKIE,
browser: true,View on GitHub (pinned to 49907e53dc)
Solutions
- Back off and retry later — cursor loops are frequently transient under rate limiting.
- Refresh authentication/session; degraded sessions often get stale cursors.
- Stop at the last good page and record the oldest post seen, treating further history as unavailable.
- Update the library if X changed cursor encoding (cursor extraction no longer matches the new value format).
- Try a fresh browser profile to bypass server-side cache stickiness.
Example fix
// before
if (nextCursor === cursor || seenCursors.has(nextCursor)) {
throw new CommandExecutionError('twitter_collection_repeated_cursor: ...');
}
// after
if (nextCursor === cursor || seenCursors.has(nextCursor)) {
console.warn('cursor loop detected; returning posts collected so far');
return { posts, receipt: completedReceipt('cursor_loop', until, pageIndex + 1, oldestSeenAt) };
} Defensive patterns
Strategy: try-catch
Validate before calling
if (nextCursor && seenCursors.has(nextCursor)) {
console.warn('cursor already seen before pagination call — cursor loop likely');
} Try / catch
try {
await paginateCollection(...);
} catch (err) {
if (String(err.message).startsWith('twitter_collection_repeated_cursor')) {
// keep posts collected so far; back off and retry or stop at cursor_exhausted
} else throw err;
} Prevention
- Back off and retry — cursor loops are often transient rate-limit artifacts.
- Refresh the session/browser profile before deep pagination runs.
- Detect repeated cursors early in your own wrapper and stop gracefully.
- Update the library if X changed cursor encoding.
- Record oldestSeenAt so partial results remain usable.
When it happens
Trigger: UserTweets returns the same bottom_cursor on consecutive pages — cursor state expired server-side, X degraded/rate-limited responses repeating a page, or repeated entries in timeline instructions causing the extractor to reuse a stale cursor.
Common situations: Very old timelines where X truncates history and repeats the last cursor; rate-limited sessions receiving cached pages; X experiment modes breaking bottom_cursor advancement; scraping accounts with huge gaps causing empty cursor-advancing pages.
Related errors
- twitter_bookmarks_repeated_cursor
- juejin recommend returned a malformed cursor
- juejin recommend returned has_more without a next cursor
- juejin cursor must be a non-negative decimal integer
- twitter_bookmarks_archive_incomplete
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/85a2e644637bb688.
Report an issue: GitHub.