jackwener/OpenCLI · error · AuthRequiredError
Not logged into x.com (no ct0 cookie)
Error message
Not logged into x.com (no ct0 cookie)
What it means
The command reads cookies for https://x.com and requires the `ct0` cookie, which Twitter/X sets on login (it is the CSRF token used with authenticated API calls). If no ct0 cookie exists, AuthRequiredError('x.com') is thrown. Without it, the follow POSTs to x.com's API would be rejected, so the command fails fast before attempting any follows.
Source
Thrown at clis/twitter/follow-batch.js:150
domain: 'x.com',
strategy: Strategy.UI,
browser: true,
args: [
{ name: 'usernames', type: 'string', positional: true, required: true, help: 'Comma-separated Twitter/X screen names, with or without @' },
{ name: 'delay-ms', type: 'int', default: DEFAULT_DELAY_MS, help: 'Delay between follow attempts in milliseconds' },
],
columns: ['username', 'status', 'message'],
func: async (page, kwargs) => {
if (!page) {
throw new CommandExecutionError('Browser session required for twitter follow-batch');
}
const usernames = parseBatchUsernames(kwargs.usernames);
const delayMs = parseDelayMs(kwargs['delay-ms']);
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((cookie) => cookie.name === 'ct0')?.value || null;
if (!ct0) {
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
}
const rows = [];
for (const [index, username] of usernames.entries()) {
if (index > 0 && delayMs > 0) {
await page.wait(delayMs / 1000);
}
rows.push(await followOne(page, username));
}
return rows;
}
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Open the connected Chrome/Chromium browser and log in to https://x.com, then re-run the command.
- Confirm the correct browser profile is being used if you have multiple profiles.
- If the session expired mid-run, re-login to refresh ct0 and other auth cookies.
- Avoid fresh --user-data-dir or cookie-clearing modes that wipe the x.com session.
Example fix
// before // headless CI, never logged in -> no ct0 // after // 1) launch the connected browser // 2) log in to https://x.com // 3) re-run: opencli twitter follow-batch 'alice,bob'
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: verify an x.com login cookie exists in the connected session
async function isLoggedInToX(page) {
const cookies = await page.getCookies({ url: 'https://x.com' });
return cookies.some((c) => c.name === 'ct0');
}
// if (!(await isLoggedInToX(page))) promptLogin('https://x.com'); Type guard
function hasCt0(cookies) {
return Array.isArray(cookies) && cookies.some((c) => c && c.name === 'ct0' && !!c.value);
} Try / catch
try {
await followBatch(usernames);
} catch (e) {
if (e.code === 'AUTH_REQUIRED' && e.domain === 'x.com') {
console.error('Log in to https://x.com in the connected Chrome, then re-run.');
await openBrowserAndPromptLogin('https://x.com');
return retry(followBatch, usernames);
}
throw e;
} Prevention
- Log into x.com in the connected browser profile before automating writes.
- Pin the automation to a persistent Chrome profile (not incognito/fresh user-data-dir).
- Re-check login state periodically; X expires sessions after security prompts.
- Don't clear cookies between runs; treat AUTH_REQUIRED as 'log in and retry', not a code bug.
When it happens
Trigger: Running `twitter follow-batch` while the connected browser profile is logged out of x.com; cookies cleared or a fresh/incognito profile in use; page.getCookies({url:'https://x.com'}) returns cookies but none named ct0 (visited x.com without logging in); the X session expired.
Common situations: Automating on a headless box where no one ever logged into X; X logged the account out after a security prompt or password change; pointing the CLI at the wrong Chrome profile; wiping cookies between runs.
Related errors
- 1point3acres Discuz *_auth cookie missing
- dianping.com
- Douban dbcl2 / ck cookies missing
- hupu.com
- jd.com
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c23d8c26ab5de3d3.
Report an issue: GitHub.