jackwener/OpenCLI · error · CommandExecutionError
Mercury returned malformed create expense click result
Error message
Mercury returned malformed create expense click result
What it means
clickCreateExpenseButton() injects a script that looks for a 'Submit expense'/'New expense' button and returns { clicked, blocked }. It throws this error when the returned payload is an object but `clicked` or `blocked` is not a boolean, meaning the browser-side script did not produce the expected contract. This is a defensive shape check before any further action is taken.
Source
Thrown at clis/mercury/utils.js:194
return style.visibility !== 'hidden' && style.display !== 'none' && node.offsetParent !== null;
})
.filter((node) => wanted.has(norm(node.innerText || node.textContent || '')));
const dangerous = candidates.find((node) => {
const container = node.closest('[role="dialog"], dialog, form, [aria-modal="true"]');
const context = String(container?.innerText || container?.textContent || '').replace(/\\s+/g, ' ').trim();
return Boolean(container) || /Review|receipt|amount|merchant|category|notes|expense date/i.test(context);
});
if (dangerous) {
return { clicked: false, blocked: true, text: dangerous.innerText || dangerous.textContent || '' };
}
const el = candidates[0];
if (!el) return { clicked: false, blocked: false };
el.click();
return { clicked: true, blocked: false, text: el.innerText || el.textContent || '' };
})()`);
const payload = assertObject(result, 'create expense click result');
if (typeof payload.clicked !== 'boolean' || typeof payload.blocked !== 'boolean') {
throw new CommandExecutionError('Mercury returned malformed create expense click result');
}
if (payload.blocked) {
throw new CommandExecutionError('Mercury is already showing a submit/review surface; refusing to click a possible final Submit expense button');
}
return payload;
}
export async function assertCreateExpenseSurface(page) {
const state = await page.evaluate(`(() => {
const text = document.body?.innerText || '';
return {
url: location.href,
title: document.title,
hasFinalSubmit: /Submit expense/i.test(text) && /Review|receipt|amount|merchant|category|notes/i.test(text),
hasForm: /receipt|amount|merchant|category|notes|expense date/i.test(text),
bodyPreview: text.replace(/\\s+/g, ' ').trim().slice(0, 600)
};
})()`);View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw evaluate result and confirm `clicked` and `blocked` are present and boolean.
- Reload the Mercury page and retry via the normal `opened` flow.
- Align page.evaluate stubs/mocks in tests with the { clicked: boolean, blocked: boolean } contract.
- Upgrade the mercury utils to the version matching the current UI.
Example fix
// before
if (typeof payload.clicked !== 'boolean' || typeof payload.blocked !== 'boolean') {
throw new CommandExecutionError('Mercury returned malformed create expense click result');
}
// after
if (typeof payload.clicked !== 'boolean' || typeof payload.blocked !== 'boolean') {
throw new CommandExecutionError(`Malformed create expense click result: ${JSON.stringify(payload)}`);
} Defensive patterns
Strategy: type-guard
Validate before calling
const payload = await page.evaluate(`(() => { ... })()`);
if (payload && typeof payload.clicked === 'boolean' && typeof payload.blocked === 'boolean') {
await clickCreateExpenseButton(page);
} Type guard
function isCreateExpenseClickResult(v) {
return v != null && typeof v === 'object'
&& typeof v.clicked === 'boolean' && typeof v.blocked === 'boolean';
} Try / catch
try {
const res = await clickCreateExpenseButton(page);
} catch (err) {
if (err instanceof CommandExecutionError && /malformed create expense click result/.test(err.message)) {
// reload page and retry once; else surface the error
} else throw err;
} Prevention
- Never stub page.evaluate in tests with shapes missing `blocked`.
- Run the create-expense flow only once per session to avoid mid-navigation evaluates.
- Reload the page before retrying after a malformed result.
- Pin the mercury utils version to one tested against the current UI.
When it happens
Trigger: The page.evaluate() injected in clickCreateExpenseButton returns an object missing or mistyping `clicked`/`blocked` — corrupted return value, mid-navigation, or a modified/older injected script.
Common situations: Mercury UI updates that break the script's early-return paths; evaluate called on a navigating/crashed page so serialization returns an unexpected value; test harnesses stubbing page.evaluate with wrong shapes.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Mercury returned malformed click result
- ${label}: ${String(payload.error)}
- ${label} returned malformed extraction payload
- coupang add-to-cart evaluation failed: ${error?.message || e
- Douyin search: unexpected evaluator payload shape
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/322b538ca7d1fe23.
Report an issue: GitHub.