jackwener/OpenCLI · error · CommandExecutionError
Following
Error message
Following
What it means
CommandExecutionError with the message built by describeTwitterApiError('Following', status). Thrown when the Following GraphQL request fails with a status other than 401/403; the helper turns the raw numeric status into a human-readable explanation for the Following endpoint.
Source
Thrown at clis/twitter/following.js:223
throw new CommandExecutionError(`Could not find user @${targetUser}`);
const allUsers = [];
const seen = new Set();
let cursor = null;
let lastRawResponse = null;
// Runaway guard only; --limit and cursor exhaustion control normal pagination.
for (let i = 0; i < MAX_PAGINATION_PAGES && allUsers.length < limit; i++) {
const fetchCount = Math.min(50, limit - allUsers.length + 10);
const apiUrl = buildFollowingUrl(followingQueryId, userId, fetchCount, cursor);
const data = unwrapBrowserResult(await page.evaluate(async (url, headers) => {
const r = await fetch(url, { headers, credentials: 'include' });
return r.ok ? await r.json() : { error: r.status };
}, apiUrl, headers));
if (data?.error) {
if (data.error === 401 || data.error === 403)
throw new AuthRequiredError('x.com', `Twitter following request failed (HTTP ${data.error})`);
throw new CommandExecutionError(describeTwitterApiError('Following', data.error));
}
lastRawResponse = data;
const { users, nextCursor } = parseFollowing(data);
for (const u of users) {
if (!seen.has(u.screen_name)) {
seen.add(u.screen_name);
allUsers.push(u);
}
}
if (!nextCursor || nextCursor === cursor)
break;
cursor = nextCursor;
}
if (allUsers.length === 0) {
if (looksLikePrivateTwitterTimeline(lastRawResponse)) {
throw new EmptyResultError('twitter following', `No following data returned for @${targetUser} (the target account may have set their following list to private)`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Read the described status: 429 means slow down — wait before retrying
- Update opencli so resolveTwitterQueryId fetches the current Following query ID
- Retry later for 5xx (Twitter-side incident)
- Lower --limit and add delays between runs to stay under rate limits
Example fix
// before: hammering the API -> 429 Error: Twitter Following request failed: HTTP 429 // after: wait, then limit results $ sleep 300 && opencli twitter following @elonmusk --limit 50
Defensive patterns
Strategy: retry
Validate before calling
// Throttle calls up front to avoid 429s
const sleep = ms => new Promise(r => setTimeout(r, ms));
for (const u of targets) {
await cli.following(u, { limit: 100 });
await sleep(15000); // stay under Twitter rate limits
} Type guard
function isRetryableApiError(err) {
const code = (/(\d{3})/.exec(String(err && err.message)) || [])[1];
return code === '429' || (code && code.startsWith('5'));
} Try / catch
try {
await cli.following(target);
} catch (err) {
if (isRetryableApiError(err)) {
const code = (/(\d{3})/.exec(err.message))[1];
await sleep(code === '429' ? 300000 : 5000);
return cli.following(target);
}
throw err;
} Prevention
- Add delays between commands to avoid 429 rate limits
- Update opencli regularly — stale query IDs cause 400s
- Watch Twitter status for 5xx incidents before bulk runs
- Keep --limit modest; smaller pages are less likely to trip limits
When it happens
Trigger: The in-page fetch of the Following API URL returns e.g. 400, 404, 429, or 5xx; data.error is truthy and not 401/403, so describeTwitterApiError('Following', data.error) is thrown, typically during pagination.
Common situations: Rate limiting (429) after aggressive pagination; stale FOLLOWING_QUERY_ID producing 400 Bad Request; Twitter 5xx outage; account restrictions returning 404 for the following tab.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- HTTP ${userLookup.error}: Failed to resolve Twitter user @${
- autohome ${contextHint} HTTP ${resp.status}
- Chess.com callback returned HTTP ${resp.status} for ${url}
- Ctrip flight API returned HTTP ${status || 'unknown'}
- dongchedi ${contextHint} HTTP ${resp.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/d54f8713b50d2873.
Report an issue: GitHub.