jackwener/OpenCLI · error · CommandExecutionError

Mercury returned malformed Review click result

Error message

Mercury returned malformed Review click result

What it means

This CLI drives the Mercury web UI via browser automation. After executing an in-page script that finds and clicks the 'Review' button, it validates the returned result object before proceeding. If the result is not an object with a boolean `clicked` field (e.g. the evaluate returned null/undefined because the script threw or the page context changed), this error is thrown because the automation cannot tell whether the click happened.

Source

Thrown at clis/mercury/reimbursement-draft.js:97

        const missing = expectedFields.filter((key) => !fields.touched[key]);
        if (missing.length > 0) {
            throw new CommandExecutionError(`Mercury reimbursement form fields were not all filled: ${missing.join(', ')}`);
        }

        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) };
            })()`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command; transient page-load races often resolve on a retry with the page fully loaded.
  2. Increase the wait before the click step so the Mercury SPA is fully rendered before evaluating the script.
  3. Verify the browser/driver session is healthy and the page has not navigated away from the expense form.
  4. If persistent, inspect whether Mercury's DOM changed such that the in-page script throws (check the browser console); update the selector/script in reimbursement-draft.js.

Example fix

// before
const reviewClick = await page.evaluate(`...`);
if (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {
    throw new CommandExecutionError('Mercury returned malformed Review click result');
}
// after
await page.wait({ time: 2 }); // ensure SPA is settled before clicking
const reviewClick = await page.evaluate(`...`);
if (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {
    throw new CommandExecutionError('Mercury returned malformed Review click result');
}
Defensive patterns

Strategy: type-guard

Validate before calling

const r = await page.evaluate(`...`);
const isClickResult = (v) => v !== null && typeof v === 'object' && typeof v.clicked === 'boolean';

Type guard

function isClickResult(v) { return v !== null && typeof v === 'object' && typeof v.clicked === 'boolean'; }

Try / catch

try {
    const reviewClick = await page.evaluate(`...`);
    if (!isClickResult(reviewClick)) throw new CommandExecutionError('Mercury returned malformed Review click result');
} catch (err) {
    if (err instanceof CommandExecutionError) throw err;
    await page.wait({ time: 2 }); // retry once after settle, then rethrow
    throw err;
}

Prevention

When it happens

Trigger: The page.evaluate snippet returning the click result yields null, undefined, a non-object, or an object without a boolean `clicked` property — e.g. the script was interrupted by a navigation, the page context was destroyed, or the browser driver returned an unexpected serialization of the result.

Common situations: Slow Mercury SPA mid-render when the evaluate runs, page navigation triggered right as the script executes, browser session/driver issues returning undefined from evaluate, or a Mercury DOM change breaking the script so it never returns a value.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/10abf21731f180f2. Report an issue: GitHub.