jackwener/OpenCLI · error · CommandExecutionError
xiaohongshu/delete-note: note ${noteId} row found but no del
Error message
xiaohongshu/delete-note: note ${noteId} row found but no delete action visible; xhs creator UI may have changed. What it means
The note row was located, but the injected script could not find a visible delete action (the inline `<span class="control data-del">` or equivalent hover control) on that row. The CLI raises CommandExecutionError because deletion cannot proceed without the action; this usually means XHS changed the row-action markup or the control is rendered under a state the script doesn't handle.
Source
Thrown at clis/xiaohongshu/delete-note.js:201
return false;
}
`)), 'published-tab');
if (!tabClicked) {
throw new CommandExecutionError('xiaohongshu/delete-note: 已发布 tab not found on note-manager; xhs creator UI may have changed.');
}
await page.wait({ time: ROW_SETTLE_MS / 1000 });
// Step 2: locate the .note row whose data-impression JSON carries the
// exact `noteId` field. Dry-run stops here; execute clicks delete.
// Substring matching on the raw attribute would risk matching unrelated
// fields whose values happen to share the noteId prefix, so parse the JSON
// and compare `noteTarget.value.noteId` explicitly.
const initResult = requireActionResult(unwrapEvaluateResult(await page.evaluate(buildLocateAndMaybeDeleteScript(noteId, execute))), 'locate-note');
if (!initResult?.ok) {
if (initResult?.kind === 'not_found') {
throw new EmptyResultError('xiaohongshu/delete-note', `Note ${noteId} not visible in the 已发布 tab. Verify the note belongs to the logged-in account and has cleared review (审核中 / 未通过 rows have no web delete entry).`);
}
if (initResult?.kind === 'no_delete_action') {
throw new CommandExecutionError(`xiaohongshu/delete-note: note ${noteId} row found but no delete action visible; xhs creator UI may have changed.`);
}
throw new CommandExecutionError('xiaohongshu/delete-note: failed to locate note row');
}
if (!execute) {
return [{ status: 'dry-run', note_id: noteId, message: 'Target note row and delete action verified. Re-run with --execute to delete.' }];
}
await page.wait({ time: MODAL_SETTLE_MS / 1000 });
// Step 3: click "确定" in the `.d-modal-footer` confirmation modal.
const confirmResult = requireActionResult(unwrapEvaluateResult(await page.evaluate(`
() => {
const isVisible = (el) => !!el && el.offsetParent !== null;
const footer = Array.from(document.querySelectorAll('.d-modal-footer')).find(isVisible);
if (!footer) return { ok: false, kind: 'no_modal' };
const buttons = Array.from(footer.querySelectorAll('button, [role="button"]')).filter(isVisible);
const confirmBtn = buttons.find((b) => (b.innerText || b.textContent || '').trim() === '确定');
if (!confirmBtn) return { ok: false, kind: 'no_confirm', labels: buttons.map(b => (b.innerText || '').trim()) };
confirmBtn.click();
return { ok: true };View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command (hover-state timing can be transient); try a wider/maximized browser window so inline actions render
- Inspect the row in DevTools to see whether the delete control still exists; if markup changed, update the library/selector logic
- Update the opencli package to the latest version that tracks the current XHS UI
- If no web delete entry truly exists for this note state, delete via the XHS mobile app instead
Defensive patterns
Strategy: retry
Validate before calling
// Pre-check the row exposes a delete control before invoking:
const hasDelete = await page.evaluate(`(id) => {
for (const row of document.querySelectorAll('.note')) {
try {
const j = JSON.parse(row.getAttribute('data-impression') || '');
if (j?.noteTarget?.value?.noteId === id) {
return !!row.querySelector('.control.data-del');
}
} catch {}
}
return false;
}`, noteId);
if (!hasDelete) throw new Error('delete action not visible on row'); Try / catch
try {
await cli('xiaohongshu', 'delete-note', { note: noteId });
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('no delete action visible')) {
await sleep(2000); // hover/settle then retry once
return cli('xiaohongshu', 'delete-note', { note: noteId });
}
throw err;
} Prevention
- Maximize the browser window so inline row actions render instead of collapsing into overflow menus
- Retry once before treating it as a UI markup change
- Keep the opencli package current; XHS changes the delete-control markup periodically
- If the note state genuinely has no web delete entry, fall back to the mobile app
When it happens
Trigger: XHS renamed/removed the .control.data-del element or changed its visibility conditions (e.g. requiring hover first in a new way); a UI variant renders actions differently; the row is in a state where no delete action exists despite being on the Published tab; element considered invisible (offsetParent null) due to layout changes.
Common situations: XHS frontend update changing action-button markup; per-account A/B layouts; browser window too narrow so action buttons collapse into an overflow menu; CSS changes making the control invisible to the offsetParent check.
Related errors
- xiaohongshu/delete-note: 已发布 tab not found on note-manager;
- dianping ${contextHint} did not render expected data${sample
- Midjourney did not expose "${config.label}" for video ${jobI
- Failed to remove @${username} from list ${listId}: ${uiResul
- Could not open the reply composer.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7e4fea06ed9c0b04.
Report an issue: GitHub.