jackwener/OpenCLI · error · CommandExecutionError
Mercury Review button was not clicked; inspect the page for
Error message
Mercury Review button was not clicked; inspect the page for validation errors
What it means
After clicking the 'Review' button via the in-page script, the automation checks the returned `clicked` flag. Mercury itself reports that no element matching the 'Review' label was found or clicked (the script returns `{ clicked: false }`). The error tells the developer to look at the rendered page — usually a form validation error is blocking progression to the Review step.
Source
Thrown at clis/mercury/reimbursement-draft.js:100
}
const reviewClick = await page.evaluate(`(() => {
const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim().toLowerCase();
const candidates = Array.from(document.querySelectorAll('button, a, [role="button"], [role="link"]'))
.filter((node) => {
const style = window.getComputedStyle(node);
return style.visibility !== 'hidden' && style.display !== 'none' && node.offsetParent !== null;
});
const el = candidates.find((node) => norm(node.innerText || node.textContent || '') === 'review');
if (!el) return { clicked: false };
el.click();
return { clicked: true, text: el.innerText || el.textContent || '' };
})()`);
if (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {
throw new CommandExecutionError('Mercury returned malformed Review click result');
}
if (!reviewClick.clicked) {
throw new CommandExecutionError('Mercury Review button was not clicked; inspect the page for validation errors');
}
await page.wait({ time: 2 });
const review = await reviewSnapshot(page);
if (!review.hasReview || !review.hasSubmitExpenseButton) {
throw new CommandExecutionError('Mercury did not reach the Review step with the final Submit expense button visible');
}
if (input.closeAfterReview) {
await page.evaluate(`(() => {
const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim().toLowerCase();
const el = Array.from(document.querySelectorAll('button, a, [role="button"], [role="link"]'))
.find((node) => norm(node.innerText || node.textContent || '') === 'close');
el?.click();
return { clicked: Boolean(el) };
})()`);
await page.wait({ time: 1 });
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the Mercury page for form validation errors and fix the underlying input (amount, date, receipt, merchant).
- Re-run with the page fully loaded; a partially rendered SPA may not expose the Review button yet.
- Check whether Mercury changed the button label/markup; update the text-match ('review') in reimbursement-draft.js if so.
- Capture a screenshot or page snapshot at failure time to confirm what state the form is in.
Example fix
// before
throw new CommandExecutionError('Mercury Review button was not clicked; inspect the page for validation errors');
// after
const snapshot = await page.evaluate(`document.body.innerText.slice(0, 2000)`);
throw new CommandExecutionError(`Mercury Review button was not clicked; page state: ${snapshot}`); Defensive patterns
Strategy: validation
Validate before calling
// before invoking, confirm the form is fully rendered and no validation errors are visible
const ready = await page.evaluate(`(() => {
const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim().toLowerCase();
return Array.from(document.querySelectorAll('button, a, [role=button], [role=link]'))
.some((n) => norm(n.innerText || n.textContent || '') === 'review');
})()`);
if (!ready) throw new Error('Review button not present; fix form validation first'); Type guard
function canClickReview(snapshot) { return snapshot.ready === true && snapshot.validationErrors.length === 0; } Try / catch
try {
await draftReimbursement(input);
} catch (err) {
if (err.message.includes('Review button was not clicked')) {
const pageText = await page.evaluate('document.body.innerText');
throw new Error(`Form blocked Review: ${pageText.slice(0, 500)}`);
}
throw err;
} Prevention
- Validate all form inputs (amount, date, receipt) before submitting upstream steps.
- Wait for full render before attempting the Review click.
- Snapshot the page on failure to capture validation banners.
- Pin/update selectors when Mercury changes its UI.
When it happens
Trigger: The in-page script found no clickable element whose normalized innerText equals 'review' (candidates.find returned undefined), so it returned `{ clicked: false }` and this error was thrown.
Common situations: Mercury form has field-level validation errors (bad amount, missing receipt/date) that hide or disable the Review button; Mercury UI redesign changed the button label from 'Review'; the page is stuck on an earlier step or showing an error banner.
Related errors
- Could not switch to ${wantModel} model
- Claude composer is not available on the current page.
- Codex sidebar extraction returned an invalid payload.
- Could not resolve a stable Codex conversation identity.
- Failed to perform action.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/48418df1d1afca70.
Report an issue: GitHub.