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
resolveUserTimelineContext drives a logged-in x.com browser session and needs the 'ct0' CSRF cookie that x.com sets for authenticated users. After loading x.com it calls page.getCookies() and throws AuthRequiredError when no ct0 cookie is present, because GraphQL calls (UserTweets, UserByScreenName) require the X-Csrf-Token header derived from it. Without ct0 the requests would be rejected as unauthenticated, so the tool fails fast.
Source
Thrown at clis/twitter/user-timeline.js:190
if (!username) {
await page.goto('https://x.com/home');
await page.wait({ selector: '[data-testid="primaryColumn"]' });
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?');
}
username = normalizeTwitterScreenName(href);
if (!username) {
throw new AuthRequiredError('x.com', 'Could not detect logged-in user. Are you logged in?');
}
}
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 userTweetsOperation = await resolveTwitterOperationMetadata(page, 'UserTweets', USER_TWEETS_OPERATION);
const userByScreenNameOperation = await resolveTwitterOperationMetadata(page, 'UserByScreenName', USER_BY_SCREEN_NAME_OPERATION);
const headers = JSON.stringify({
Authorization: `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
'X-Csrf-Token': ct0,
'X-Twitter-Auth-Type': 'OAuth2Session',
'X-Twitter-Active-User': 'yes',
});
const userByScreenNameUrl = buildUserByScreenNameUrl(userByScreenNameOperation, username);
const userId = unwrapBrowserResult(await page.evaluate(`async () => {
const resp = await fetch(${JSON.stringify(userByScreenNameUrl)}, { headers: ${headers}, credentials: 'include' });
if (!resp.ok) return null;
const data = await resp.json();
return data?.data?.user?.result?.rest_id || null;
}`));
if (!userId) throw new CommandExecutionError(`Could not resolve @${username}`);
return { username, userId, headers, userTweetsOperation };View on GitHub (pinned to 49907e53dc)
Solutions
- Log into x.com in the browser session/profile the tool uses (complete the login flow manually in that browser, then retry).
- Persist the browser profile (user-data-dir / storageState) so cookies survive between runs.
- Verify the page actually reaches https://x.com before getCookies is called; if x.com redirects to a login page, re-authenticate.
- Re-run after clearing stale state if x.com invalidated the session; if cookie names changed upstream, update the cookie lookup.
Example fix
// before: reusing a throwaway context
const page = await browser.newPage();
await runTimeline(page, 'someuser');
// after: reuse a persistent, logged-in profile
const ctx = await browser.createBrowserContext({
userDataDir: '/home/me/.opencli/x-profile' // already logged into x.com
});
const page = await ctx.newPage();
await runTimeline(page, 'someuser'); 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('Run the login flow for x.com before fetching the timeline.');
} Try / catch
try {
await fetchUserTimeline(page, username);
} catch (err) {
if (err instanceof AuthRequiredError) {
await runXLoginFlow(page); // open x.com/login, wait for user
return fetchUserTimeline(page, username);
}
throw err;
} Prevention
- Persist the browser profile (user-data-dir/storageState) so the x.com session survives restarts.
- Check for the ct0 cookie at startup and trigger the login flow proactively.
- Re-login after password changes or x.com security signouts.
When it happens
Trigger: Calling the user-timeline command/`context` flow when the Puppeteer/Playwright page used by resolveUserTimelineContext is not logged into x.com: fresh browser profile with no session, expired session cookies, logged-out/incognito context, or x.com failing to set the ct0 cookie on the loaded page.
Common situations: Running the CLI for the first time without ever logging into x.com in the automation profile; x.com logged the session out server-side (password change, security event); using a data dir that was wiped; x.com A/B changes altering cookie names; running against a page that landed on a login or error page instead of x.com.
Related errors
- csrftoken cookie missing - make sure you are logged in to In
- csrftoken cookie missing - make sure you are logged in to In
- 12306 tk auth cookie missing
- amazon.com
- Facebook c_user cookie missing — anonymous session
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/87b7bd0a3de73001.
Report an issue: GitHub.