{"record":{"id":"5017326ebd031311","repo":"jackwener/OpenCLI","slug":"not-logged-into-x-com-no-ct0-cookie-501732","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/lists.js","lineNumber":126,"sourceCode":"\nexport const command = cli({\n    site: 'twitter',\n    name: 'lists',\n    access: 'read',\n    description: 'Get Twitter/X lists for the logged-in user (owned + subscribed)',\n    domain: 'x.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'limit', type: 'int', default: 50, help: 'Maximum number of lists to return (default 50).' },\n    ],\n    columns: ['id', 'name', 'members', 'followers', 'mode'],\n    func: async (page, kwargs) => {\n        const limit = kwargs.limit || 50;\n        const cookies = await page.getCookies({ url: 'https://x.com' });\n        const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;\n        if (!ct0)\n            throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');\n        // opencli >=1.7.x wraps primitive page.evaluate returns as { session, data: <value> }.\n        const unwrap = (v) => (v && typeof v === 'object' && 'session' in v && 'data' in v ? v.data : v);\n        const queryIdRaw = await page.evaluate(`async () => {\n            try {\n                const ghResp = await fetch('https://raw.githubusercontent.com/fa0311/twitter-openapi/refs/heads/main/src/config/placeholder.json');\n                if (ghResp.ok) {\n                    const data = await ghResp.json();\n                    const entry = data['${OPERATION_NAME}'];\n                    if (entry && entry.queryId) return entry.queryId;\n                }\n            } catch {}\n            try {\n                const scripts = performance.getEntriesByType('resource')\n                    .filter(r => r.name.includes('client-web') && r.name.endsWith('.js'))\n                    .map(r => r.name);\n                for (const scriptUrl of scripts.slice(0, 15)) {\n                    try {\n                        const text = await (await fetch(scriptUrl)).text();","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/lists.js#L108-L144","documentation":"Same guard as list-tweets but in the `twitter lists` command: enumerating your lists requires the ct0 CSRF cookie from an authenticated x.com session. If page.getCookies({url:'https://x.com'}) finds no ct0, the command throws AuthRequiredError immediately.","triggerScenarios":"Running `twitter lists` with a logged-out browser profile, expired session, cleared cookies, or a profile where x.com cookies were never stored.","commonSituations":"Fresh automation profile never logged in; X invalidated the session server-side; a script clears cookies between runs; pointing at the wrong user-data-dir.","solutions":["Log into x.com in the controlled browser/profile, then re-run `opencli twitter lists`","Check for both ct0 and auth_token cookies via page.getCookies({url:'https://x.com'})","Use/point to the persistent profile that holds your X session","Automate a pre-flight auth check before batches of twitter commands"],"exampleFix":"// before\nconst lists = await run('twitter', 'lists', {}); // AuthRequiredError if logged out\n// after\nconst cookies = await page.getCookies({ url: 'https://x.com' });\nconst authed = cookies.some(c => c.name === 'ct0') && cookies.some(c => c.name === 'auth_token');\nif (!authed) throw new Error('Not logged into x.com; log in first.');\nconst lists = await run('twitter', 'lists', {});","handlingStrategy":"validation","validationCode":"const cookies = await page.getCookies({ url: 'https://x.com' });\nif (!cookies.some(c => c.name === 'ct0')) throw new Error('Log into x.com before running `twitter lists`.');","typeGuard":"const hasCt0 = (cookies) => Array.isArray(cookies) && cookies.some(c => c.name === 'ct0' && c.value);","tryCatchPattern":"try {\n  const lists = await run('twitter', 'lists', { limit: 50 });\n} catch (e) {\n  if (e.name === 'AuthRequiredError' || /no ct0 cookie/.test(e.message)) {\n    console.error('x.com session missing — log in with the automation profile, then retry.');\n  } else throw e;\n}","preventionTips":["Keep one persistent, logged-in profile for all twitter commands","Run `twitter lists` (a cheap read) as an auth probe before heavier flows","Don't wipe cookies between commands","Refresh login when auth_token/ct0 disappear"],"tags":["auth","cookies","csrf"],"backgroundTag":"missing-auth-cookie","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}