{"record":{"id":"1ccb2f7dd241d674","repo":"jackwener/OpenCLI","slug":"draft-row-id-still-exists-after-delete","errorCode":null,"errorMessage":"Draft ${row.id} still exists after delete","messagePattern":"Draft (.+?) still exists after delete","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/draft-delete.js","lineNumber":94,"sourceCode":"        const entries = await readDraftEntries(page, draftType);\n        const entry = findDraftEntry(entries, id);\n        if (!entry) throw draftNotFound(id, draftType, 'xiaohongshu/draft-delete');\n        const row = normalizeDraftRecord(entry.row, entry.key, draftType, 1);\n        if (!execute) {\n            return [{\n                status: 'dry-run',\n                id: row.id,\n                type: draftType,\n                message: 'Draft exists. Re-run with --execute to delete.',\n            }];\n        }\n        const storeName = STORE_NAME_MAP[draftType];\n        const result = unwrapBrowserResult(await page.evaluate(deleteDraftScript(storeName, entry.key)));\n        if (!result?.ok) {\n            throw new CommandExecutionError(result?.error || `Failed to delete draft ${row.id}`);\n        }\n        if (!result.deleted) {\n            throw new CommandExecutionError(`Draft ${row.id} still exists after delete`);\n        }\n        return [{\n            status: 'deleted',\n            id: row.id,\n            type: draftType,\n            message: 'Draft deleted.',\n        }];\n    },\n});\n","sourceCodeStart":76,"sourceCodeEnd":104,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/draft-delete.js#L76-L104","documentation":"Thrown by draft-delete.js when the delete script reports ok but result.deleted is falsy, meaning the script completed yet the draft record is still present in the store. This is a post-condition check to guarantee the delete actually took effect.","triggerScenarios":"Running delete with --execute when deleteDraftScript returns { ok: true, deleted: false } — typically because the record with entry.key no longer matched at verification time, the key encoding (encodeDraftKey) does not match the actual key type (string vs number), or the transaction committed without removing the record.","commonSituations":"Key type mismatch: IndexedDB keys are numeric but the script looked up a string key; drafts refreshed between lookup and delete; XHS schema change altering the primary key path.","solutions":["Re-run the command without --execute to refresh the entry key, then delete again","Check key type handling in encodeDraftKey/deleteDraftScript (s: string vs numeric keys)","Verify the object store's keyPath in DevTools matches what the script queries","Report/update the library if XHS changed its draft store key structure"],"exampleFix":"// before\nconst result = unwrapBrowserResult(await page.evaluate(deleteDraftScript(storeName, entry.key)));\nif (!result.deleted) throw new CommandExecutionError(`Draft ${row.id} still exists after delete`);\n// after\n// refresh entry.key with a fresh dry-run lookup first:\nconst fresh = await lookupDraft(page, draftType, row.id); // no --execute\nconst result = unwrapBrowserResult(await page.evaluate(deleteDraftScript(storeName, fresh.key)));","handlingStrategy":"retry","validationCode":"const entry = await lookupDraft(page, draftType, id);\nif (!entry?.key) throw new Error(`Draft ${id} already gone`);","typeGuard":"function wasDeleted(r) {\n  return r != null && typeof r === 'object' && r.ok === true && r.deleted === true;\n}","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try { await draftDelete({ type, id, execute: true }); break; }\n  catch (e) {\n    if (!/still exists after delete/.test(e.message)) throw e;\n    await lookupDraft(page, type, id); // refresh key before retrying\n  }\n}","preventionTips":["Refresh the entry key (dry-run lookup) between delete attempts","Confirm the draft store's keyPath/key type matches encodeDraftKey's s: string encoding","Avoid mutating drafts in the XHS UI while the delete command runs","Check for XHS schema changes if this error starts appearing consistently"],"tags":["indexeddb","cli","delete-failed","state-inconsistency"],"backgroundTag":"draft-still-exists-after-delete","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}