Problem
When adding a non-USD (e.g. UK/GB) business bank account, the signer/director verification step can get permanently stuck on the "hang tight" screen with no way to go back or restart. Under the hood the SaveCorpayOnboardingDirectorInformation request is submitted with a blank signerEmail, which fails a required-field check, so the flow never progresses.
This is a frontend bug: the director form does not carry forward the signer email that was already entered/stored earlier in the flow. Instead it re-derives signerEmail from the currently logged-in user's account.primaryLogin. When that value is empty (or belongs to the wrong account), a blank signerEmail is shipped.
Copilot/delegate trigger
This is especially reproducible in a Copilot (delegated access) session. When a delegate is acting on another user's account, account.primaryLogin reflects the delegate's state (and can also go stale/blank right after a delegate switch), so the value fed into signerEmail is wrong for the account being acted on. It can also occur in a normal session whenever account.primaryLogin is unhydrated at submit time (e.g. after a remove/re-add of the bank account).
Affected flows
The bug lives in the shared non-USD Corpay onboarding code, so it affects both:
- Global Reimbursement (Workflows/Payments → connect manually → non-USD setup)
- Expensify Card UK/EU enrollment
Both entry points converge on the same NonUSD setup wizard and the same signer components, so QA should cover both.
Root cause (frontend)
signerEmail is derived from account?.primaryLogin ?? '' in both signer/director submission paths:
There is no fallback if that value is empty, so a blank signerEmail is submitted and rejected by the backend's required-field validation. (The backend relays the frontend value verbatim and has no server-side fallback either — the email the user entered is already stored earlier in the flow, it's just not reused here.)
Suggested fix
Source signerEmail from the account being acted on / the value already captured earlier in the flow (e.g. the stored reimbursementAccount.achData.corpay.signerEmail or session.email) rather than account.primaryLogin — at minimum whenever a Copilot/delegate session is active. Apply the same change to both submission paths above.
QA
- Complete UK/non-USD bank account signer/director verification in a normal session → succeeds.
- Complete it in a Copilot/delegate session → succeeds (previously stuck on "hang tight").
- Verify via both the Global Reimbursement and Expensify Card UK/EU entry points.
Reported from an internal investigation in Expensify/Expensify#664293.
Issue Owner
Current Issue Owner: @situchan
Problem
When adding a non-USD (e.g. UK/GB) business bank account, the signer/director verification step can get permanently stuck on the "hang tight" screen with no way to go back or restart. Under the hood the
SaveCorpayOnboardingDirectorInformationrequest is submitted with a blanksignerEmail, which fails a required-field check, so the flow never progresses.This is a frontend bug: the director form does not carry forward the signer email that was already entered/stored earlier in the flow. Instead it re-derives
signerEmailfrom the currently logged-in user'saccount.primaryLogin. When that value is empty (or belongs to the wrong account), a blanksignerEmailis shipped.Copilot/delegate trigger
This is especially reproducible in a Copilot (delegated access) session. When a delegate is acting on another user's account,
account.primaryLoginreflects the delegate's state (and can also go stale/blank right after a delegate switch), so the value fed intosignerEmailis wrong for the account being acted on. It can also occur in a normal session wheneveraccount.primaryLoginis unhydrated at submit time (e.g. after a remove/re-add of the bank account).Affected flows
The bug lives in the shared non-USD Corpay onboarding code, so it affects both:
Both entry points converge on the same NonUSD setup wizard and the same signer components, so QA should cover both.
Root cause (frontend)
signerEmailis derived fromaccount?.primaryLogin ?? ''in both signer/director submission paths:src/pages/ReimbursementAccount/NonUSD/SignerInfo/index.tsx:58-60(in-line director flow)src/pages/ReimbursementAccount/EnterSignerInfo/index.tsx:44-52(emailed-signer flow)There is no fallback if that value is empty, so a blank
signerEmailis submitted and rejected by the backend's required-field validation. (The backend relays the frontend value verbatim and has no server-side fallback either — the email the user entered is already stored earlier in the flow, it's just not reused here.)Suggested fix
Source
signerEmailfrom the account being acted on / the value already captured earlier in the flow (e.g. the storedreimbursementAccount.achData.corpay.signerEmailorsession.email) rather thanaccount.primaryLogin— at minimum whenever a Copilot/delegate session is active. Apply the same change to both submission paths above.QA
Reported from an internal investigation in Expensify/Expensify#664293.
Issue Owner
Current Issue Owner: @situchan