{"record":{"id":"f6b569a9b53e047d","repo":"jackwener/OpenCLI","slug":"could-not-find-the-mercury-submit-expense-or-new-e","errorCode":null,"errorMessage":"Could not find the Mercury Submit expense or New expense button","messagePattern":"Could not find the Mercury Submit expense or New expense button","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/mercury/reimbursement-draft.js","lineNumber":54,"sourceCode":"        { name: 'ocr-wait-seconds', default: '8', help: 'Seconds to wait after receipt upload before correcting OCR-overwritten fields' },\n        { name: 'close-after-review', type: 'boolean', default: false, help: 'Close the Review dialog after verification; final Submit is still never clicked' },\n    ],\n    columns: ['status', 'url', 'receipt', 'uploaded', 'fieldsTouched', 'reviewReady', 'submitBlocked', 'warnings'],\n    func: async (page, kwargs) => {\n        const input = normalizeReimbursementInput(kwargs);\n        const before = await inspectMercury(page);\n        assertLoggedIn(before);\n\n        await page.goto(MERCURY_EXPENSES_URL, { waitUntil: 'load', settleMs: 1500 });\n        await page.wait({ time: 1 });\n        const createSurface = await assertCreateExpenseSurface(page);\n        if (createSurface.hasFinalSubmit && /review/i.test(createSurface.bodyPreview || '')) {\n            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        }","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/reimbursement-draft.js#L36-L72","documentation":"After opening the create-expense surface, the flow calls clickCreateExpenseButton; if no button matching 'Submit expense' or 'New expense' is found/clickable, it throws CommandExecutionError. This means Mercury's UI did not present the expected create-expense entry point, so the automation cannot proceed safely.","triggerScenarios":"Running reimbursement-draft when Mercury's UI changed (selectors/markup updated), the user lacks permission to create expenses, the account/workspace shows a different expenses layout, the page loaded partially (network slowness), or an unexpected interstitial (2FA, onboarding, error banner) replaced the normal view.","commonSituations":"Mercury product UI updates breaking selectors; new workspaces with restricted roles; A/B-tested layouts; slow loads where the button hasn't rendered before the click attempt; sessions landing on a different locale's labels.","solutions":["Log in manually and confirm the 'Submit expense'/'New expense' button exists on the expenses page; complete any interstitials (onboarding, verification) first.","Refresh the page or restart the browser session and retry once the page fully loads.","Verify your Mercury user has permission to create/submit expenses in the workspace.","If the button exists but the automation still fails, the selectors in clis/mercury/reimbursement-draft.js (assertCreateExpenseSurface/clickCreateExpenseButton) are likely stale — update them or report the Mercury UI change upstream."],"exampleFix":"// before (partial load)\nawait page.goto(MERCURY_EXPENSES_URL, { waitUntil: 'load' });\nconst opened = await clickCreateExpenseButton(page);\n// after (ensure surface settled before clicking)\nawait page.goto(MERCURY_EXPENSES_URL, { waitUntil: 'load', settleMs: 3000 });\nawait page.wait({ selector: 'button', timeout: 10 });\nconst opened = await clickCreateExpenseButton(page);","handlingStrategy":"try-catch","validationCode":"// preflight: confirm the create-expense button is present before invoking\nconst ok = await page.evaluate(`!![...document.querySelectorAll('button')]\n  .find(b => /(submit expense|new expense)/i.test(b.textContent || ''))`);\nif (!ok) throw new Error('Create-expense button not on page; load fully or check permissions');","typeGuard":null,"tryCatchPattern":"try {\n  await draftReimbursement(page, data);\n} catch (e) {\n  if (/Could not find the Mercury Submit expense/.test(e.message)) {\n    console.error('Reload the expenses page, clear interstitials, verify permissions, or update stale selectors');\n  } else throw e;\n}","preventionTips":["Wait for full page load/settling before clicking; add selector waits.","Complete any onboarding/2FA interstitials manually before automating.","Confirm the Mercury role has expense-creation permissions.","After Mercury UI releases, re-verify selectors in clis/mercury/reimbursement-draft.js and update them promptly."],"tags":["browser-automation","selector-not-found","mercury","command-execution-error"],"backgroundTag":"ui-selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}