jackwener/OpenCLI · error · AuthRequiredError
Twitter device-follow returned HTTP ${data.error}
Error message
Twitter device-follow returned HTTP ${data.error} What it means
When the GraphQL response parses but carries an error status of 401 or 403, the command throws AuthRequiredError for x.com with the HTTP code embedded. This means the session's credentials were rejected by the API rather than the response being malformed.
Source
Thrown at clis/twitter/device-follow.js:167
if (!r.ok) return { error: r.status };
try {
return await r.json();
} catch (e) {
return { errorKind: 'non_json', detail: String(e && e.message || e) };
}
} catch (e) {
return { errorKind: 'exception', detail: String(e && e.message || e) };
}
}`);
if (data?.errorKind === 'non_json') {
throw new CommandExecutionError(`Twitter device-follow returned non-JSON response: ${data.detail || 'unknown parse error'}`);
}
if (data?.errorKind === 'exception') {
throw new CommandExecutionError(`Twitter device-follow fetch failed: ${data.detail || 'unknown error'}`);
}
if (data?.error) {
if (data.error === 401 || data.error === 403) {
throw new AuthRequiredError('x.com', `Twitter device-follow returned HTTP ${data.error}`);
}
throw new CommandExecutionError(describeTwitterApiError('device_follow', data.error));
}
const parsed = parseDeviceFollow(data, new Set());
if (!parsed) {
throw new CommandExecutionError('Twitter device-follow response was missing the expected timeline/globalObjects shape.');
}
if (parsed.malformedEntries > 0 || parsed.unmatchedTweetEntries > 0) {
throw new CommandExecutionError('Twitter device-follow entries could not be joined to tweet/user objects.');
}
if (parsed.rows.length === 0) {
throw new EmptyResultError('twitter device-follow', 'No device-follow notification tweets found.');
}
const rows = parsed.rows;
const trimmed = rows.slice(0, limit);
return applyTopByEngagement(trimmed, kwargs['top-by-engagement']);
},
});View on GitHub (pinned to 49907e53dc)
Solutions
- Log out and back into x.com to refresh the session and ct0 cookie
- Clear x.com cookies in the CLI-managed profile and re-authenticate
- Verify the whole cookie jar comes from the same session (don't mix ct0 from one profile with another session)
- If 403 persists on a clean session, the account/IP may be flagged — wait or switch networks
Example fix
// before (stale cookies) cli twitter device-follow # AuthRequiredError: HTTP 401 // after # clear x.com cookies in the managed profile, log in again, then cli twitter device-follow
Defensive patterns
Strategy: fallback
Validate before calling
const cookies = await page.getCookies({ url: 'https://x.com' });
const ok = cookies.some((c) => c.name === 'ct0' && c.value);
// also ensure cookies all come from one session/profile Try / catch
try {
await cli.twitter.deviceFollow();
} catch (e) {
if (e instanceof AuthRequiredError && /HTTP 40[13]/.test(e.message)) {
console.error('Session rejected — clear x.com cookies and log in again.');
return await reauthenticateThen(fn);
}
throw e;
} Prevention
- Re-login after password changes; old sessions get 401
- Keep the ct0 cookie and auth token from the same browser session
- Switch IP / avoid datacenter IPs to reduce 403 bot-flag risk
- Rotate re-authentication routinely for long-running scrapers
When it happens
Trigger: The device_follow API responds with HTTP 401 (expired/invalid auth token or csrf mismatch) or 403 (forbidden — suspended account, bot detection, or token/cookie pair out of sync).
Common situations: Stale bearer token after x.com rotated keys; ct0 cookie not matching the session (copied cookies from another browser); account flagged or suspended; IP flagged by Twitter's anti-bot system.
Related errors
- Flomo API returned HTTP ${resp.status}; please refresh your
- Gmail ${operation} returned HTTP ${status}
- 未登录或登录已过期,请先在浏览器中登录贝壳找房
- LinkedIn Learning auth failed (HTTP ${result.status ?? ''}).
- linux.do requires an active signed-in browser session
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5e1e5793625f3cdc.
Report an issue: GitHub.