{"record":{"id":"b0248f675dece610","repo":"jackwener/OpenCLI","slug":"failed-to-delete-list-listid-list-still-appear","errorCode":null,"errorMessage":"Failed to delete list ${listId}: list still appears in managed lists.","messagePattern":"Failed to delete list (.+?): list still appears in managed lists\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-delete.js","lineNumber":153,"sourceCode":"            if (!editDialog) return { ok: false, message: 'Edit List dialog did not open' };\n            const deleteButton = findButton('Delete List');\n            if (!deleteButton) return { ok: false, message: 'Delete List button not found' };\n            deleteButton.click();\n            await sleep(800);\n            const confirmButton = document.querySelector('[data-testid=\"confirmationSheetConfirm\"]')\n                || findButton('Delete');\n            if (!confirmButton) return { ok: false, message: 'Delete confirmation button not found' };\n            confirmButton.click();\n            await sleep(2500);\n            return { ok: true, url: location.href };\n        })()`));\n        if (!deleteResult?.ok) {\n            throw new CommandExecutionError(`Failed to delete list ${listId}: ${deleteResult?.message || 'unknown UI failure'}`);\n        }\n\n        const listsAfter = await getManagedLists(page, headers);\n        if (listsAfter.some((list) => list.id === listId)) {\n            throw new CommandExecutionError(`Failed to delete list ${listId}: list still appears in managed lists.`);\n        }\n\n        return [buildListDeleteRow({ listId, targetList })];\n    },\n});\n","sourceCodeStart":135,"sourceCodeEnd":159,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-delete.js#L135-L159","documentation":"After the in-page delete click-through reports success, list-delete re-fetches your managed lists via the ListsManagementPageTimeline GraphQL call and asserts the list is gone. If the listId is still present in that post-delete listing, it throws this CommandExecutionError — the UI flow looked successful but the deletion was not actually effective (or the cache/read lagged).","triggerScenarios":"deleteResult.ok was true (confirm button clicked, 2.5s slept), but getManagedLists() still returns an entry with the same id. Causes: the confirmation click actually cancelled/dismissed the sheet, the server rejected the delete while the UI optimistically navigated away, X rendered a stale managed-lists timeline, or the deleted list was a follower/subscribed list that re-appears in the management fetch.","commonSituations":"X.com eventual consistency — the ListsManagementPageTimeline endpoint serves a cached timeline immediately after delete; clicking 'Delete' on a list you don't own (subscriber view still shows delete-looking controls in some layouts); the wrong confirmation button was clicked closing the dialog without deleting.","solutions":["Wait 30–60 seconds and re-run `opencli twitter lists` to confirm whether the list actually still exists before retrying","Re-run the delete command — a first attempt may have silently dismissed the confirmation sheet; the retry usually verifies gone","Open https://x.com/i/lists/<listId> in a browser: if it 404s, the list is deleted and this was a stale-read false positive","Verify you own the list (owner-only deletes take effect; subscriptions can't be deleted this way)","If it consistently persists, delete it manually in the UI and inspect whether the confirm button selector is clicking the wrong element"],"exampleFix":"// before (immediate post-delete verification)\nconst listsAfter = await getManagedLists(page, headers);\n// after (allow cache lag before verification)\nawait sleep(5000);\nconst listsAfter = await getManagedLists(page, headers);","handlingStrategy":"retry","validationCode":"// Post-failure existence check before treating it as a hard failure:\nconst stillThere = (await run('opencli twitter lists')).some(r => r.listId === listId);\nif (!stillThere) console.log('List actually deleted; stale-read false positive');","typeGuard":"function listIsReallyGone(lists, listId) {\n  return Array.isArray(lists) && !lists.some(l => String(l.id) === String(listId));\n}","tryCatchPattern":"const MAX_ATTEMPTS = 2;\nfor (let i = 1; i <= MAX_ATTEMPTS; i++) {\n  try {\n    await run(`opencli twitter list-delete ${listId} --confirm true`);\n    break;\n  } catch (e) {\n    const stillThere = (await run('opencli twitter lists')).some(r => r.listId === listId);\n    if (!stillThere) break;                 // verification lag, list is gone\n    if (i === MAX_ATTEMPTS) throw e;         // genuine persistence\n    await new Promise(r => setTimeout(r, 30000)); // let X.com caches settle\n  }\n}","preventionTips":["Treat a single occurrence as suspected stale read — re-check `opencli twitter lists` before escalating","Wait a minute after the failure and verify via the lists command or the list URL (404 = deleted)","Confirm you own the list; subscription/follower lists won't be removed by this delete flow","If it persists across retries, the confirmation click is likely hitting the wrong button — test the UI manually"],"tags":["browser-automation","verification","eventual-consistency","twitter"],"backgroundTag":"delete-not-verified","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}