jackwener/OpenCLI · error · TimeoutError
twitter followers API capture
Error message
twitter followers API capture
What it means
The command triggers an SPA navigation to /{user}/followers and waits up to CAPTURE_TIMEOUT_SECONDS (10s) for the intercepted /Followers GraphQL request via page.waitForCapture. If no matching response is observed in time, the wait's rejection is converted into a TimeoutError naming the operation and timeout. This means X never issued (or the interceptor never saw) a Followers API call after the navigation.
Source
Thrown at clis/twitter/followers.js:142
throw new AuthRequiredError('x.com', 'Could not find logged-in user profile link. Are you logged in?');
}
}
if (!targetUser) {
throw new ArgumentError('twitter followers user cannot be empty', 'Example: opencli twitter followers @elonmusk --limit 100');
}
await page.installInterceptor('/Followers?');
const targetPath = `/${targetUser}/followers`;
await page.evaluate(`() => {
const targetPath = ${JSON.stringify(targetPath)};
window.history.pushState({}, '', targetPath);
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
}`);
try {
await page.waitForCapture(CAPTURE_TIMEOUT_SECONDS);
}
catch {
throw new TimeoutError('twitter followers API capture', CAPTURE_TIMEOUT_SECONDS, 'No Followers response was observed after opening the followers list.');
}
const currentPath = unwrapBrowserResult(await page.evaluate('() => window.location.pathname'));
if (typeof currentPath !== 'string' || !currentPath.toLowerCase().endsWith('/followers')) {
throw new CommandExecutionError('SPA navigation to Twitter followers failed');
}
const allFollowers = [];
const seen = new Set();
let cursor = null;
let lastRawResponse = null;
let pages = 0;
const consumeCaptured = async () => {
const requests = await page.getInterceptedRequests();
if (!Array.isArray(requests)) {
throw new CommandExecutionError('Twitter followers interceptor returned malformed responses');
}
for (const request of requests) {View on GitHub (pinned to 49907e53dc)
Solutions
- Retry — transient slowness often resolves; consider increasing CAPTURE_TIMEOUT_SECONDS
- Verify you can open https://x.com/{user}/followers manually in the same browser profile
- Try a different target account (the target may be private/suspended)
- Update the interceptor pattern in followers.js if X renamed the Followers endpoint
- Re-authenticate if the page is redirecting to login
Example fix
// before const CAPTURE_TIMEOUT_SECONDS = 10; // after const CAPTURE_TIMEOUT_SECONDS = 30;
Defensive patterns
Strategy: retry
Validate before calling
// pre-check that the followers page loads for this account
const res = await fetch('https://x.com/' + handle + '/followers', { headers: { cookie } });
if (res.redirected && res.url.includes('/login')) throw new Error('auth wall for ' + handle); Type guard
null
Try / catch
try {
const rows = await opencli.twitter.followers(user, { limit });
} catch (err) {
if (err instanceof TimeoutError && err.message.includes('API capture')) {
await sleep(3000);
return opencli.twitter.followers(user, { limit }); // one retry
} else throw err;
} Prevention
- Retry transient timeouts with backoff before failing
- Skip accounts whose followers page is private/suspended (check manually first)
- Raise CAPTURE_TIMEOUT_SECONDS on slow networks
- Keep the interceptor pattern updated with X endpoint names
When it happens
Trigger: The followers page requires login (redirect to /login), the account is suspended/protected so no Followers request fires, the interceptor pattern '/Followers?' no longer matches X's endpoint path, the popstate navigation failed, or the network is slow beyond 10 seconds.
Common situations: Target account is private/suspended so X never loads the followers list; X changed the GraphQL operation path; x.com is serving a login wall despite a ct0 cookie; heavy rate-limiting or a network hiccup.
Related errors
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- FETCH_ERROR
- archive wayback request failed: ${error?.message || error}
- Bilibili creator comparison
- Bilibili relation modify did not verify ${expectedLabel}; la
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/653ca6b0d4d8ed48.
Report an issue: GitHub.