{"record":{"id":"9af28a35e59f5d86","repo":"jackwener/OpenCLI","slug":"mercury-receipt-upload-did-not-confirm-the-intende","errorCode":null,"errorMessage":"Mercury receipt upload did not confirm the intended receipt input","messagePattern":"Mercury receipt upload did not confirm the intended receipt input","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/mercury/reimbursement-draft.js","lineNumber":67,"sourceCode":"            throw new CommandExecutionError('Mercury appears to have an existing expense review open; refusing to click a possible final Submit expense button');\n        }\n\n        const opened = await clickCreateExpenseButton(page);\n        if (!opened.clicked) {\n            throw new CommandExecutionError('Could not find the Mercury Submit expense or New expense button');\n        }\n\n        await page.wait({ time: 2 });\n\n        if (!page.uploadFiles) {\n            throw new CommandExecutionError('Mercury reimbursement-draft requires Browser Bridge uploadFiles support to verify the intended receipt input');\n        }\n        const upload = await page.uploadFiles(RECEIPT_INPUT_SELECTOR, [input.receipt]);\n        if (!upload || upload.uploaded !== true || upload.files !== 1) {\n            throw new CommandExecutionError('Mercury receipt upload did not confirm exactly one uploaded file');\n        }\n        if (upload.target !== RECEIPT_INPUT_SELECTOR || upload.matches_n !== 1) {\n            throw new CommandExecutionError('Mercury receipt upload did not confirm the intended receipt input');\n        }\n        const uploadedNames = Array.isArray(upload.file_names) ? upload.file_names : [];\n        if (!uploadedNames.includes(receiptBasename(input.receipt))) {\n            throw new CommandExecutionError('Mercury receipt upload did not confirm the expected receipt file');\n        }\n\n        if (input.ocrWaitSeconds > 0) await page.wait({ time: input.ocrWaitSeconds });\n\n        const fields = await fillReimbursementFields(page, input);\n        await page.wait({ time: 1 });\n        const expectedFields = ['amount', 'currency', 'date', 'merchant', 'category', 'notes'];\n        const missing = expectedFields.filter((key) => !fields.touched[key]);\n        if (missing.length > 0) {\n            throw new CommandExecutionError(`Mercury reimbursement form fields were not all filled: ${missing.join(', ')}`);\n        }\n\n        const reviewClick = await page.evaluate(`(() => {\n            const norm = (s) => String(s || '').replace(/\\\\s+/g, ' ').trim().toLowerCase();","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/reimbursement-draft.js#L49-L85","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before (utils.js)\nexport const RECEIPT_INPUT_SELECTOR = 'input[type=file]';\n// after\nexport const RECEIPT_INPUT_SELECTOR = 'form input[type=file][accept=\"image/*,.pdf\"]';","handlingStrategy":"validation","validationCode":"const matches = document.querySelectorAll('input[type=file]').length;\nif (matches !== 1) {\n  throw new Error(`expected exactly 1 file input, found ${matches}; tighten RECEIPT_INPUT_SELECTOR`);\n}","typeGuard":"function targetsExpectedInput(upload, selector) {\n  return upload?.target === selector && upload?.matches_n === 1;\n}","tryCatchPattern":"try {\n  await uploadReceipt(page, selector, files);\n} catch (e) {\n  if (String(e.message).includes('did not confirm the intended receipt input')) {\n    // close extra overlays, tighten selector, retry\n  } else throw e;\n}","preventionTips":["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]."],"tags":["selector-mismatch","browser-automation","file-upload","mercury"],"backgroundTag":"selector-ambiguity","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}