jackwener/OpenCLI · error · CommandExecutionError
twitter_collection_request_error
twitter_collection_request_error
Error message
twitter_collection_request_error: UserTweets returned ${payload.error} What it means
paginateCollection checks each UserTweets payload for an error property before parsing. If the GraphQL response carries an error (auth failure, rate limit, bad cursor, etc.), the library surfaces it as twitter_collection_request_error including the API's own error text, aborting pagination since no completeness can be proven from an errored page.
Source
Thrown at clis/twitter/collection.js:265
completed: true,
stop_reason: stopReason,
requested_until: until.toISOString(),
pages_fetched: pagesFetched,
oldest_seen_at: oldestSeenAt ? oldestSeenAt.toISOString() : null,
};
}
async function paginateCollection({ until, limit, maxPages = MAX_USER_TWEETS_PAGES, fetchPage, wait }) {
const seen = new Set();
const seenCursors = new Set();
const posts = [];
let cursor = null;
let oldestSeenAt = null;
for (let pageIndex = 0; pageIndex < maxPages; pageIndex++) {
if (pageIndex > 0 && wait) await wait();
const payload = await fetchPage(cursor, USER_TWEETS_PAGE_SIZE);
if (payload?.error) {
throw new CommandExecutionError(`twitter_collection_request_error: UserTweets returned ${payload.error}`);
}
const [pagePosts, nextCursor] = parseCollectionPage(payload, seen);
for (const post of pagePosts) {
if (posts.length >= limit) {
throw new CommandExecutionError('twitter_collection_limit_reached: pagination cannot prove completion');
}
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 {View on GitHub (pinned to 49907e53dc)
Solutions
- Read payload.error in the message and address the specific X error (rate limit → back off and retry later; auth → refresh cookies/session).
- Refresh authentication before long collection runs to avoid mid-pagination token expiry.
- Update the library's queryId/GraphQL operation hashes if X deployed a new frontend version.
- Add exponential backoff between pages instead of a fixed wait.
- Reduce maxPages/page size to stay under rate limits for large accounts.
Example fix
// before
for (let pageIndex = 0; pageIndex < maxPages; pageIndex++) {
if (pageIndex > 0 && wait) await wait();
// after
for (let pageIndex = 0; pageIndex < maxPages; pageIndex++) {
if (pageIndex > 0 && wait) await wait(Math.min(baseDelay * 2 ** pageIndex, cap)); // backoff against rate limits Defensive patterns
Strategy: retry
Validate before calling
if (payload?.error) {
console.error('X GraphQL error before pagination:', payload.error);
return;
} Type guard
function isCleanPayload(payload) {
return payload != null && typeof payload === 'object' && !('error' in payload);
} Try / catch
try {
await paginateCollection(...);
} catch (err) {
if (String(err.message).startsWith('twitter_collection_request_error')) {
await backoffRetry(maxAttempts, baseDelayMs); // handle rate limit / auth errors
} else throw err;
} Prevention
- Check payload.error before each page and surface the API error text.
- Use exponential backoff between pages to avoid 429 rate limits.
- Refresh auth cookies before long collection runs.
- Keep queryId/operation hashes current after X frontend deploys.
- Cap maxPages/page size for large accounts to stay within limits.
When it happens
Trigger: fetchPage returns a payload with truthy .error — X GraphQL errors such as rate limiting (429/TooManyRequests), expired auth cookies, invalid queryId after an X deploy, or cursor invalidated by account changes.
Common situations: Long-running paginations exceeding X rate limits; stale queryId in the bundled GraphQL request after X ships a new frontend build; expired guest/session token mid-run; network proxy injecting error JSON.
Related errors
- ${describeTwitterApiError('SearchTimeline', data.error)}
- ${describeTwitterApiError('TweetDetail', data.error)}
- ${describeTwitterApiError(endpoint, data.error)}
- ${describeTwitterApiError('UserTweets', data.error)}
- ${probe.detail}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c264b3d40e5eca9e.
Report an issue: GitHub.