jackwener/OpenCLI · error · CommandExecutionError
Mercury receipt upload did not confirm the intended receipt
Error message
Mercury receipt upload did not confirm the intended receipt input
What it means
Thrown when the uploadFiles result reports a successful single-file upload but against the wrong target — `upload.target !== RECEIPT_INPUT_SELECTOR` or `upload.matches_n !== 1`. The library requires that exactly one element matching the expected receipt input selector received the file; ambiguity or a remapped target means the receipt may have landed in the wrong input.
Source
Thrown at clis/mercury/reimbursement-draft.js:67
throw new CommandExecutionError('Mercury appears to have an existing expense review open; refusing to click a possible final Submit expense button');
}
const opened = await clickCreateExpenseButton(page);
if (!opened.clicked) {
throw new CommandExecutionError('Could not find the Mercury Submit expense or New expense button');
}
await page.wait({ time: 2 });
if (!page.uploadFiles) {
throw new CommandExecutionError('Mercury reimbursement-draft requires Browser Bridge uploadFiles support to verify the intended receipt input');
}
const upload = await page.uploadFiles(RECEIPT_INPUT_SELECTOR, [input.receipt]);
if (!upload || upload.uploaded !== true || upload.files !== 1) {
throw new CommandExecutionError('Mercury receipt upload did not confirm exactly one uploaded file');
}
if (upload.target !== RECEIPT_INPUT_SELECTOR || upload.matches_n !== 1) {
throw new CommandExecutionError('Mercury receipt upload did not confirm the intended receipt input');
}
const uploadedNames = Array.isArray(upload.file_names) ? upload.file_names : [];
if (!uploadedNames.includes(receiptBasename(input.receipt))) {
throw new CommandExecutionError('Mercury receipt upload did not confirm the expected receipt file');
}
if (input.ocrWaitSeconds > 0) await page.wait({ time: input.ocrWaitSeconds });
const fields = await fillReimbursementFields(page, input);
await page.wait({ time: 1 });
const expectedFields = ['amount', 'currency', 'date', 'merchant', 'category', 'notes'];
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();View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the expense dialog DOM and make RECEIPT_INPUT_SELECTOR more specific so it matches exactly one input element.
- Update RECEIPT_INPUT_SELECTOR in clis/mercury/utils.js to the new Mercury markup after a UI change.
- Close any other open dialogs/overlays on the page before running the command so only the expense form's input matches.
- Add an explicit id or data attribute path to the selector (e.g. input[type=file][accept*=image]) to disambiguate.
Example fix
// before (utils.js) export const RECEIPT_INPUT_SELECTOR = 'input[type=file]'; // after export const RECEIPT_INPUT_SELECTOR = 'form input[type=file][accept="image/*,.pdf"]';
Defensive patterns
Strategy: validation
Validate before calling
const matches = document.querySelectorAll('input[type=file]').length;
if (matches !== 1) {
throw new Error(`expected exactly 1 file input, found ${matches}; tighten RECEIPT_INPUT_SELECTOR`);
} Type guard
function targetsExpectedInput(upload, selector) {
return upload?.target === selector && upload?.matches_n === 1;
} Try / catch
try {
await uploadReceipt(page, selector, files);
} catch (e) {
if (String(e.message).includes('did not confirm the intended receipt input')) {
// close extra overlays, tighten selector, retry
} else throw e;
} Prevention
- Keep RECEIPT_INPUT_SELECTOR strict enough to match exactly one node.
- Close other dialogs/overlays before running the command.
- After Mercury UI updates, re-count matching nodes in DevTools before running.
- Prefer attribute-qualified selectors (accept, form scope) over bare input[type=file].
When it happens
Trigger: Running reimbursement-draft when Mercury's DOM changed so the selector matches 0 or multiple elements (matches_n != 1), or the bridge resolved the upload to a different selector/target than RECEIPT_INPUT_SELECTOR (e.g. a second hidden file input on the page).
Common situations: Mercury UI update introducing an additional file input (e.g. drag-and-drop zone plus classic input); a dialog overlay containing a duplicate input; selector defined too loosely in utils.js so it matches multiple nodes.
Related errors
- Mercury receipt upload did not confirm exactly one uploaded
- Mercury reimbursement-draft requires Browser Bridge uploadFi
- Mercury receipt upload did not confirm the expected receipt
- Booking.com page declared results but no property cards were
- Failed to attach file
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9af28a35e59f5d86.
Report an issue: GitHub.