{"record":{"id":"2bd226df788650c8","repo":"jackwener/OpenCLI","slug":"not-logged-into-x-com-no-ct0-cookie-2bd226","errorCode":null,"errorMessage":"Not logged into x.com (no ct0 cookie)","messagePattern":"Not logged into x\\.com \\(no ct0 cookie\\)","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-create.js","lineNumber":115,"sourceCode":"    description: 'Create a new Twitter/X list (returns the new list id)',\n    access: 'write',\n    domain: 'x.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'name', positional: true, type: 'string', required: true, help: `List name (max ${NAME_MAX} chars)` },\n        { name: 'description', type: 'string', default: '', help: `Optional list description (max ${DESCRIPTION_MAX} chars)` },\n        { name: 'mode', type: 'string', default: 'public', help: 'public | private' },\n    ],\n    columns: ['id', 'name', 'description', 'mode', 'status'],\n    func: async (page, kwargs) => {\n        const { listName: name, listDescription: description, listMode: mode, privateFlag: isPrivate } = parseListCreateArgs(kwargs);\n\n        await page.goto('https://x.com');\n        await page.wait(3);\n        const cookies = await page.getCookies({ url: 'https://x.com' });\n        const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;\n        if (!ct0) throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');\n\n        // Hardcode queryId: it must match the FEATURES schema below.\n        // Letting resolveTwitterQueryId() drift would pull a newer queryId\n        // whose schema would reject our simplified features payload.\n        const queryId = CREATE_LIST_QUERY_ID;\n\n        const headers = JSON.stringify({\n            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,\n            'X-Csrf-Token': ct0,\n            'X-Twitter-Auth-Type': 'OAuth2Session',\n            'X-Twitter-Active-User': 'yes',\n            'Content-Type': 'application/json',\n        });\n        const body = JSON.stringify({\n            variables: { isPrivate, name, description },\n            features: FEATURES,\n            queryId,\n        });","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-create.js#L97-L133","documentation":"The list-create command authenticates to x.com by reading the ct0 CSRF cookie from the browser session. If no ct0 cookie exists after navigating to https://x.com, the user is not logged in, so the command throws AuthRequiredError instead of making authenticated GraphQL calls that would fail anyway.","triggerScenarios":"page.getCookies({ url: 'https://x.com' }) returns no cookie named 'ct0' after page.goto('https://x.com') — i.e. no active x.com session in the automation browser.","commonSituations":"Running the CLI without ever logging into x.com in the automation browser; session expired/logged out; cookies cleared or isolated browser profile; incognito profile without stored cookies.","solutions":["Log into x.com in the automation browser session, then re-run the command","Re-run `opencli` login/session bootstrap for Twitter if the CLI provides one","Check you are using the same browser profile that holds the x.com session","Clear corrupted cookies and log in again if ct0 is stale"],"exampleFix":"// before\nopencli twitter list-create \"My List\"\n// after\nopencli twitter login   # establish x.com session first\nopencli twitter list-create \"My List\"","handlingStrategy":"try-catch","validationCode":"const cookies = await page.getCookies({ url: 'https://x.com' });\nconst hasCt0 = cookies.some((c) => c.name === 'ct0' && c.value);\nif (!hasCt0) throw new Error('Not logged into x.com — run login first');","typeGuard":"function isLoggedIn(cookies) {\n  return Array.isArray(cookies) && cookies.some((c) => c.name === 'ct0' && !!c.value);\n}","tryCatchPattern":"try {\n  await runListCreate(page, kwargs);\n} catch (e) {\n  if (e instanceof AuthRequiredError && /ct0/.test(e.message)) {\n    console.error('Run `opencli twitter login` and retry.');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Log into x.com once per automation profile and reuse it","Check login state at script start before batch operations","Treat AuthRequiredError as a distinct exit code in CI"],"tags":["auth","cookie","csrf","twitter"],"backgroundTag":"missing-auth-cookie","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}