{"record":{"id":"9fb9a97d0d86fd6c","repo":"jackwener/OpenCLI","slug":"twitter-unlike-confirmation","errorCode":null,"errorMessage":"twitter unlike confirmation","messagePattern":"twitter unlike confirmation","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"warning","filePath":"clis/twitter/unlike.js","lineNumber":74,"sourceCode":"            // Click Unlike\n            writeStarted = true;\n            unlikeBtn.click();\n            await new Promise(r => setTimeout(r, 1000));\n\n            // Verify success by checking if the 'like' button reappeared\n            const verifyArticle = findTargetArticle() || targetArticle;\n            const verifyBtn = verifyArticle?.querySelector('[data-testid=\"like\"]');\n            if (verifyBtn) {\n                return { ok: true, message: 'Tweet successfully unliked.' };\n            } else {\n                return { ok: false, unconfirmed: true, message: 'Unlike action was initiated but UI did not update as expected.' };\n            }\n        } catch (e) {\n            return { ok: false, unconfirmed: writeStarted, message: e.toString() };\n        }\n    })()`);\n        if (result.unconfirmed) {\n            throw new TimeoutError('twitter unlike confirmation', 1, `${result.message} Check the tweet before retrying; the unlike may already have succeeded.`);\n        }\n        if (!result.ok) {\n            throw new CommandExecutionError(result.message, 'Nothing changed. Open the tweet in the browser and retry.');\n        }\n        await page.wait(2);\n        return [{\n                status: 'success',\n                message: result.message\n            }];\n    }\n});\n","sourceCodeStart":56,"sourceCodeEnd":86,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/unlike.js#L56-L86","documentation":"After clicking Unlike inside the page, the in-page script returns `unconfirmed: true` when the write was initiated but the UI never verified success (the 'like' button did not reappear within the verification window, or an in-page exception fired after the click). The CLI maps that to a TimeoutError named 'twitter unlike confirmation' with a 1-unit timeout. This is deliberately treated as ambiguous: the unlike may have actually succeeded on x.com even though the UI did not reflect it.","triggerScenarios":"Clicking the Unlike button succeeded but the follow-up DOM check for `[data-testid=\"like\"]` did not pass within ~1s; an exception thrown inside the page script after `writeStarted = true` (line 57-58 of unlike.js) also sets `unconfirmed: true`.","commonSituations":"Slow X.com rendering or network lag so the optimistic UI update is delayed; tweet deleted or conversation view changed mid-operation; X.com A/B DOM changes moving the verification selector; rate-limiting or an error toast replacing the article content.","solutions":["Do NOT immediately retry blindly — open the tweet in the browser and manually verify whether the like is already gone; retry only if it is still liked.","Re-run `opencli twitter unlike <url>` after verifying state; the command is idempotent (it reports 'already unliked' if the like button is present).","If it happens consistently, check for X.com DOM changes affecting `[data-testid=\"like\"]`/`[data-testid=\"unlike\"]` and update the selectors.","Increase network stability / retry after a short wait if the UI was merely slow to update."],"exampleFix":"// before\nopencli twitter unlike $URL && opencli twitter unlike $URL   # blind retry can double-click state\n// after\nopencli twitter unlike $URL || { opencli browser open $URL; }  # verify in browser, then retry once","handlingStrategy":"try-catch","validationCode":"// confirm state before retrying: is the tweet still liked?\nconst stillLiked = await page.evaluate(`!!document.querySelector('[data-testid=\"like\"]')`);\nif (!stillLiked) console.log('Already unliked; skip retry');","typeGuard":"function isUnconfirmedTimeout(e) {\n  return e instanceof TimeoutError && e.name === 'twitter unlike confirmation';\n}","tryCatchPattern":"try {\n  await cli.run(['twitter', 'unlike', tweetUrl]);\n} catch (e) {\n  if (isUnconfirmedTimeout(e)) {\n    // verify in browser before retrying; the unlike may already have succeeded\n    const confirmed = await manuallyVerifyUnliked(tweetUrl);\n    if (confirmed) return;\n    await retryWithBackoff(() => cli.run(['twitter', 'unlike', tweetUrl]), 1);\n  } else throw e;\n}","preventionTips":["Never blind-retry after a confirmation timeout — check the tweet state first.","Ensure a stable network connection so UI updates render within the ~1s verification window.","Keep selectors/testids in sync if you fork or patch the command.","Treat this error as ambiguous state and make retries idempotent."],"tags":["timeout","ui-verification","twitter","ambiguous-state"],"backgroundTag":"unconfirmed-write-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}