{"record":{"id":"21f4519a3654ee21","repo":"jackwener/OpenCLI","slug":"not-logged-into-x-com-no-ct0-cookie-21f451","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-delete.js","lineNumber":98,"sourceCode":"        { name: 'listId', positional: true, type: 'string', required: true, help: 'Numeric ID of the list you own (e.g. from `opencli twitter lists`)' },\n        { name: 'confirm', type: 'boolean', default: false, help: 'Required. Set --confirm true to delete the list.' },\n        { name: 'timeout', type: 'int', default: 300, help: 'Max seconds for the overall delete command (default: 300)' },\n    ],\n    columns: ['listId', 'name', 'members', 'status', 'message'],\n    func: async (page, kwargs) => {\n        const listId = String(kwargs.listId || '').trim();\n        if (!listId || !/^\\d+$/.test(listId)) {\n            throw new ArgumentError(`Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected numeric ID.`, 'Example: opencli twitter list-delete 123456789 --confirm true');\n        }\n        if (!normalizeConfirm(kwargs.confirm)) {\n            throw new ArgumentError('Refusing to delete list without --confirm true', 'Example: opencli twitter list-delete 123456789 --confirm true');\n        }\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        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        });\n\n        const listsBefore = await getManagedLists(page, headers);\n        const targetList = listsBefore.find((list) => list.id === listId);\n        if (!targetList) {\n            throw new CommandExecutionError(`List ${listId} not found among your lists (${listsBefore.length} lists fetched).`);\n        }\n\n        await page.goto(`https://x.com/i/lists/${listId}`);\n        await page.wait({ selector: '[data-testid=\"primaryColumn\"]' });\n        const deleteResult = unwrapBrowserResult(await page.evaluate(`(async () => {\n            const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-delete.js#L80-L116","documentation":"list-delete reads the ct0 CSRF cookie from the x.com session to build authenticated API headers. If the cookie is absent, the session is not logged in and the command throws AuthRequiredError rather than attempting unauthenticated deletes that would fail. Same guard as list-create.","triggerScenarios":"After page.goto('https://x.com') and page.wait(3), getCookies({ url: 'https://x.com' }) finds no 'ct0' cookie — no active x.com login in the automation browser.","commonSituations":"Never logged into x.com in the automation browser; session expired or revoked; cookies cleared between runs; using a different browser profile than the one holding the login.","solutions":["Log into x.com in the automation browser, then re-run the delete command","Run the CLI's Twitter login/bootstrap step to establish the session","Ensure the same browser profile is reused across runs","Re-login to refresh expired cookies"],"exampleFix":"// before\nopencli twitter list-delete 123456789 --confirm true\n// after\nopencli twitter login\nopencli twitter list-delete 123456789 --confirm true","handlingStrategy":"try-catch","validationCode":"const cookies = await page.getCookies({ url: 'https://x.com' });\nif (!cookies.some((c) => c.name === 'ct0' && c.value)) {\n  throw new Error('x.com session missing — authenticate before deleting lists');\n}","typeGuard":"function hasSessionCookie(cookies) {\n  return Array.isArray(cookies) && cookies.some((c) => c.name === 'ct0' && !!c.value);\n}","tryCatchPattern":"try {\n  await runListDelete(page, kwargs);\n} catch (e) {\n  if (e instanceof AuthRequiredError && /ct0/.test(e.message)) {\n    await twitterLogin();\n    await runListDelete(page, kwargs);\n  } else throw e;\n}","preventionTips":["Reuse a persistent logged-in browser profile","Re-authenticate when cookies expire between runs","Pre-flight auth check before batch delete operations"],"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"}