{"record":{"id":"66770f84ea668f2f","repo":"jackwener/OpenCLI","slug":"xiaohongshu-delete-note-confirmation-modal-step-f","errorCode":null,"errorMessage":"xiaohongshu/delete-note: confirmation modal step failed (${confirmResult?.kind ?? 'unknown'})","messagePattern":"xiaohongshu/delete-note: confirmation modal step failed \\((.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/delete-note.js","lineNumber":223,"sourceCode":"            if (!execute) {\n                return [{ status: 'dry-run', note_id: noteId, message: 'Target note row and delete action verified. Re-run with --execute to delete.' }];\n            }\n            await page.wait({ time: MODAL_SETTLE_MS / 1000 });\n            // Step 3: click \"确定\" in the `.d-modal-footer` confirmation modal.\n            const confirmResult = requireActionResult(unwrapEvaluateResult(await page.evaluate(`\n      () => {\n        const isVisible = (el) => !!el && el.offsetParent !== null;\n        const footer = Array.from(document.querySelectorAll('.d-modal-footer')).find(isVisible);\n        if (!footer) return { ok: false, kind: 'no_modal' };\n        const buttons = Array.from(footer.querySelectorAll('button, [role=\"button\"]')).filter(isVisible);\n        const confirmBtn = buttons.find((b) => (b.innerText || b.textContent || '').trim() === '确定');\n        if (!confirmBtn) return { ok: false, kind: 'no_confirm', labels: buttons.map(b => (b.innerText || '').trim()) };\n        confirmBtn.click();\n        return { ok: true };\n      }\n    `)), 'confirm-modal');\n            if (!confirmResult?.ok) {\n                throw new CommandExecutionError(`xiaohongshu/delete-note: confirmation modal step failed (${confirmResult?.kind ?? 'unknown'})`);\n            }\n            // Step 4: poll for row removal (proves the delete actually committed,\n            // not just the modal was clicked). Iteration-bounded rather than\n            // wall-clock so tests with a mocked `page.wait` exhaust the loop\n            // quickly instead of stalling on real time.\n            const VERIFY_ITERATIONS = Math.ceil(VERIFY_TIMEOUT_MS / VERIFY_POLL_MS);\n            let stillPresent = true;\n            for (let i = 0; i < VERIFY_ITERATIONS; i++) {\n                await page.wait({ time: VERIFY_POLL_MS / 1000 });\n                const probe = requireEvaluateBoolean(unwrapEvaluateResult(await page.evaluate(buildVerifyGoneScript(noteId))), 'verify-gone');\n                if (probe === false) {\n                    stillPresent = false;\n                    break;\n                }\n            }\n            if (stillPresent) {\n                throw new CommandExecutionError(`xiaohongshu/delete-note: note ${noteId} still visible after confirm click; deletion may not have committed.`);\n            }","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/delete-note.js#L205-L241","documentation":"Step 3 clicks 确定 (Confirm) in the .d-modal-footer confirmation modal after clicking delete. The script reported ok:false with a kind (e.g. 'no_modal', 'no_confirm') or an unknown shape, so the CLI throws this CommandExecutionError naming the failing kind. The delete was initiated but never confirmed, so nothing was deleted.","triggerScenarios":"The confirmation modal did not appear within MODAL_SETTLE_MS (2s); XHS changed the modal markup (.d-modal-footer class removed/renamed) so no confirm button is found; the confirm button label no longer matches 确定; the modal rendered but buttons were invisible to the offsetParent check.","commonSituations":"Slow rendering past the 2s modal settle window; XHS frontend update altering modal classes; browser window/zoom making the modal render off-layout; a different dialog variant (A/B test) with different button markup.","solutions":["Re-run the command; if the modal was just slow, a retry may succeed (consider increasing MODAL_SETTLE_MS if configurable)","Inspect the confirm modal in DevTools: if .d-modal-footer or the 确定 button markup changed, update the selector logic in the library","Update the opencli package to the latest version tracking the current XHS UI","Maximize the browser window / reset zoom so the modal renders normally","IMPORTANT: because the delete was initiated but not confirmed, verify in the browser whether the note still exists before retrying to avoid double-delete attempts"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await cli('xiaohongshu', 'delete-note', { note: noteId });\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.includes('confirmation modal step failed')) {\n    // Deletion was initiated but NOT confirmed — verify current state before retrying\n    const stillThere = await noteStillListed(noteId);\n    if (stillThere) return cli('xiaohongshu', 'delete-note', { note: noteId });\n    return; // already deleted\n  }\n  throw err;\n}","preventionTips":["Always re-check whether the note still exists before retrying — the delete click already fired","Maximize the window / reset zoom so the confirm modal renders normally","Retry with a longer settle delay if the modal is slow to appear","Keep opencli updated for XHS modal markup (.d-modal-footer / 确定) changes"],"tags":["ui-automation","dom-change","modal"],"backgroundTag":"ui-selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}