jackwener/OpenCLI · error · CommandExecutionError
Mercury returned malformed click result
Error message
Mercury returned malformed click result
What it means
clickText() runs a page.evaluate() script in the browser to find and click a button/link matching the given labels, then validates the returned payload. The library throws this CommandExecutionError when the evaluate() result is an object but its `clicked` field is not a boolean, i.e. the browser-side script returned an unexpected shape instead of { clicked: boolean, ... }. This guards against silently acting on malformed automation results from a changed or broken page environment.
Source
Thrown at clis/mercury/utils.js:165
}
export async function clickText(page, labels) {
const result = await page.evaluate(`(() => {
const labels = ${JSON.stringify(labels)};
const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim().toLowerCase();
const wanted = labels.map(norm);
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) => wanted.includes(norm(node.innerText || node.textContent || '')));
if (!el) return { clicked: false, labels };
el.click();
return { clicked: true, text: el.innerText || el.textContent || '' };
})()`);
const payload = assertObject(result, 'click result');
if (typeof payload.clicked !== 'boolean') throw new CommandExecutionError('Mercury returned malformed click result');
return payload;
}
export async function clickCreateExpenseButton(page) {
const result = await page.evaluate(`(() => {
const norm = (s) => String(s || '').replace(/\\s+/g, ' ').trim().toLowerCase();
const wanted = new Set(['submit expense', 'new expense']);
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;
})
.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);
});View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw `result` from page.evaluate() before the throw and check its shape for the `clicked` key.
- Ensure the page is fully loaded and not navigated mid-evaluate; re-run inspectMercury() then retry clickText().
- Update to a matching version of the mercury CLI utils so the evaluate script and its validation agree.
- Catch CommandExecutionError and retry with a fresh page if it is transient.
Example fix
// before
const payload = assertObject(result, 'click result');
if (typeof payload.clicked !== 'boolean') throw new CommandExecutionError('Mercury returned malformed click result');
// after
const payload = assertObject(result, 'click result');
if (typeof payload.clicked !== 'boolean') {
console.error('click result was', JSON.stringify(result));
throw new CommandExecutionError(`Mercury returned malformed click result: ${JSON.stringify(result)}`);
} Defensive patterns
Strategy: type-guard
Validate before calling
const payload = await page.evaluate(`(() => { ... })()`);
if (payload && typeof payload === 'object' && typeof payload.clicked === 'boolean') {
await clickText(page, ['Save']);
} Type guard
function isClickResult(v) {
return v != null && typeof v === 'object' && typeof v.clicked === 'boolean';
} Try / catch
try {
const res = await clickText(page, ['Save']);
} catch (err) {
if (err instanceof CommandExecutionError && /malformed click result/.test(err.message)) {
// re-inspect page state and retry on a fresh evaluate
} else throw err;
} Prevention
- Log raw evaluate results in debug mode to spot shape drift early.
- Keep page.evaluate scripts and their validators in the same function so they cannot drift.
- Wrap automation steps with retry-once-on-fresh-page logic.
- Add a pre-check (inspectMercury) that the page is loaded and stable before clicking.
When it happens
Trigger: page.evaluate() returns an object lacking a boolean `clicked` property — e.g. the injected script was altered, an older/cached script version is running, or the page context returned a proxy/non-serializable value that deserialized differently.
Common situations: Automating a Mercury page whose DOM/context changed so evaluate returns an unexpected shape; custom page wrappers or patched evaluate implementations that transform results; browser extensions injecting scripts that interfere with evaluate return values.
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 create expense 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/4be181734b0c4074.
Report an issue: GitHub.