jackwener/OpenCLI · error · AuthRequiredError
x.com
Error message
x.com
What it means
AuthRequiredError with domain 'x.com' and message 'Not logged into x.com (no ct0 cookie)'. The twitter following command reads the browser's cookies for https://x.com and requires the ct0 cookie (X's CSRF token, only issued to authenticated sessions). Its absence means the shared browser profile has no active x.com login, so the authenticated GraphQL Followers endpoints cannot be called.
Source
Thrown at clis/twitter/following.js:154
},
{ name: 'limit', type: 'int', default: 50, help: 'Maximum number of following rows to return (default 50). Must be a positive integer.' },
],
columns: ['screen_name', 'name', 'bio', 'followers'],
func: async (page, kwargs) => {
const limit = kwargs.limit === undefined || kwargs.limit === null ? 50 : Number(kwargs.limit);
if (!Number.isInteger(limit) || limit <= 0) {
throw new ArgumentError('twitter following --limit must be a positive integer', 'Example: opencli twitter following @elonmusk --limit 200');
}
const rawUser = String(kwargs.user ?? '').trim();
let targetUser = normalizeScreenName(rawUser);
if (rawUser && !targetUser) {
throw new ArgumentError('twitter following user must be a valid Twitter/X handle', 'Example: opencli twitter following @elonmusk --limit 200');
}
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;
if (!ct0)
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
if (!targetUser) {
// Force a navigation to the home surface so the AppTabBar sidebar
// is rendered; the framework pre-nav lands on bare x.com which
// does not always expose AppTabBar_Profile_Link.
await page.goto('https://x.com/home');
await page.wait({ selector: '[data-testid="primaryColumn"]' });
// Bridge wraps primitive page.evaluate returns as { session, data:<value> };
// unwrap so the href string is usable downstream.
// NOTE: the function-literal form `() => ...` silently drops
// primitive return values through the bridge — only the template
// string form preserves the `data` field.
const href = unwrapBrowserResult(await page.evaluate(`() => {
const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
return link ? link.getAttribute('href') : null;
}`));
if (!href || typeof href !== 'string')
throw new AuthRequiredError('x.com', 'Could not detect logged-in user. Are you logged in?');View on GitHub (pinned to 49907e53dc)
Solutions
- Log into x.com once in the automation browser profile so ct0 (and auth_token) cookies are issued.
- Re-run the command after confirming x.com shows you logged in in that profile.
- If X keeps logging you out, re-authenticate and avoid sharing the profile with tools that clear cookies.
- Persist a dedicated browser profile for opencli so the session survives restarts.
Example fix
// before # browser profile not logged in -> no ct0 opencli twitter following @elonmusk // after # log into x.com in the automation browser first, then: opencli twitter following @elonmusk --limit 200
Defensive patterns
Strategy: validation
Validate before calling
const cookies = await page.getCookies({ url: 'https://x.com' });
if (!cookies.some(c => c.name === 'ct0')) {
throw new Error('Not logged into x.com: log in once in the automation browser profile before running this command');
} Type guard
const hasSession = (cookies) => Array.isArray(cookies) && cookies.some(c => c.name === 'ct0' && c.value);
Try / catch
import { AuthRequiredError } from '@jackwener/opencli/errors';
try {
rows = await opencli.twitter.following(user, { limit });
} catch (e) {
if (e instanceof AuthRequiredError && /no ct0 cookie/.test(e.message)) {
await launchInteractiveLogin('https://x.com'); // one-time manual login, then retry
rows = await opencli.twitter.following(user, { limit });
} else throw e;
} Prevention
- Log into x.com once in the dedicated automation browser profile
- Persist that profile so cookies (ct0, auth_token) survive restarts
- Avoid cookie-clearing privacy tools on the automation profile
- Re-authenticate promptly when X force-logs the session out
When it happens
Trigger: page.getCookies({url:'https://x.com'}) returns no cookie named 'ct0' — the automation browser was never logged into x.com, the session was logged out, or cookies were cleared/expired.
Common situations: Fresh automation profile with no prior manual login; X forced a logout (password change, suspicious-activity signout); cookie purge by browser housekeeping or a privacy tool; session expired after long inactivity.
Related errors
- 12306 tk auth cookie missing
- amazon.com
- Facebook c_user cookie missing — anonymous session
- csrftoken cookie missing - make sure you are logged in to In
- csrftoken cookie missing - make sure you are logged in to In
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/42b09b96873b7acd.
Report an issue: GitHub.