You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2026-05-07] [$500] Expense - Map expense is shown instead scan expense. #86248
Version Number: V9.3.43-0 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught during regression testing, add the test name, ID and link from BrowserStack:#85589 Email or phone of affected tester (no customers):dreamnitethedragon+yydyd373@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Redminote 10S Android 13 App Component: Money Requests
Line 999: if (iouType !== TRACK && isDistanceRequest && ...) { createDistanceRequest(...); return; }
Line 1007: if (iouType === SPLIT && receiptFiles.length) { startSplitBill(...); return; }
If the draft transaction retains iouRequestType: 'distance' when the user switches to the scan tab, isDistanceRequest returns true and a distance expense is created — even though the user captured receipt photos.
The draft retains the stale type because of a guard in IOURequestStartPage.tsx:233-248: the useFocusEffect skips calling resetIOUTypeIfChanged when transaction?.reportID === reportID. After completing a split distance expense and immediately starting a new split from the same room, the old draft (with iouRequestType: 'distance') may still be present because cleanup is deferred via InteractionManager.runAfterInteractions. If the OnyxTabNavigator also doesn't fire onTabSelected (because the persisted tab already matches), resetIOUTypeIfChanged is never called, and the draft keeps iouRequestType: 'distance'.
What changes do you think we should make in order to solve the problem?
The distance check at line 999 should not take priority when the user has receipt files. Add a receipt-file guard to the distance check condition:
Where hasReceiptFiles is Object.values(receiptFiles).some(Boolean). This ensures that when the user has captured receipt photos, the flow falls through to the scan/split receipt path at line 1007 instead of creating a distance expense.
What alternative solutions did you explore? (Optional)
An alternative is to fix the useFocusEffect guard in IOURequestStartPage.tsx to always call resetIOUTypeIfChanged when the transaction type doesn't match the selected tab, regardless of whether the reportID matches. However, this is riskier since that guard exists to avoid resetting the transaction for other legitimate reasons (e.g., test transactions). The confirmation-level fix is more defensive and directly prevents the symptom.
Supporting evidence
Control flow in the submit handler (IOURequestStepConfirmation.tsx):
Line 999: Distance check → createDistanceRequest and return
Line 1007: Split with receipts → startSplitBill and return
Line 1048: Split from room → splitBill and return
The distance check at step 1 preempts the receipt check at step 2.
Draft cleanup race condition (IOU/Split.ts:266): After splitBill completes, draft cleanup is deferred via InteractionManager.runAfterInteractions(() => removeDraftTransaction(...)). If the user starts a new split before this fires, the old draft persists.
Tab navigator skip (OnyxTabNavigator.tsx:195-202): When the persisted tab in Onyx matches the current tab, onTabSelected is not called on mount, so resetIOUTypeIfChanged doesn't fire.
useFocusEffect guard (IOURequestStartPage.tsx:237): transaction?.reportID === reportID causes early return when starting a new split from the same room — preventing re-initialization.
Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot <your feedback> to refine this analysis, or explain why you are rejecting Melvin's proposal.
changed the title [-][Due for payment 2026-05-07] [$250] Expense - Map expense is shown instead scan expense.[/-][+][Due for payment 2026-05-07] [$500] Expense - Map expense is shown instead scan expense.[/+]on May 5, 2026
[Contributor] The offending PR and associated issue have been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.
Unfortunately, I did not find a suitable PR
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: NA
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
Regression Test Proposal
Test:
Open App
Create workspace
Go to Track Distance > Map > enter waypoints > Next
Kill the app
Long press the app icon to access the “3D touch” menu > scan receipt
Activity
MelvinBot commentedon Apr 14, 2026
Proposal
What is the root cause of that problem?
When submitting a split expense in
IOURequestStepConfirmation.tsx:999, the distance request check runs before the scan receipt check at line 1007:If the draft transaction retains
iouRequestType: 'distance'when the user switches to the scan tab,isDistanceRequestreturnstrueand a distance expense is created — even though the user captured receipt photos.The draft retains the stale type because of a guard in
IOURequestStartPage.tsx:233-248: theuseFocusEffectskips callingresetIOUTypeIfChangedwhentransaction?.reportID === reportID. After completing a split distance expense and immediately starting a new split from the same room, the old draft (withiouRequestType: 'distance') may still be present because cleanup is deferred viaInteractionManager.runAfterInteractions. If theOnyxTabNavigatoralso doesn't fireonTabSelected(because the persisted tab already matches),resetIOUTypeIfChangedis never called, and the draft keepsiouRequestType: 'distance'.What changes do you think we should make in order to solve the problem?
The distance check at line 999 should not take priority when the user has receipt files. Add a receipt-file guard to the distance check condition:
At
IOURequestStepConfirmation.tsx:999, add a check that there are no receipt files before entering the distance path:Where
hasReceiptFilesisObject.values(receiptFiles).some(Boolean). This ensures that when the user has captured receipt photos, the flow falls through to the scan/split receipt path at line 1007 instead of creating a distance expense.What alternative solutions did you explore? (Optional)
An alternative is to fix the
useFocusEffectguard inIOURequestStartPage.tsxto always callresetIOUTypeIfChangedwhen the transaction type doesn't match the selected tab, regardless of whether thereportIDmatches. However, this is riskier since that guard exists to avoid resetting the transaction for other legitimate reasons (e.g., test transactions). The confirmation-level fix is more defensive and directly prevents the symptom.Supporting evidence
Control flow in the submit handler (
IOURequestStepConfirmation.tsx):createDistanceRequestand returnstartSplitBilland returnsplitBilland returnThe distance check at step 1 preempts the receipt check at step 2.
Draft cleanup race condition (
IOU/Split.ts:266): AftersplitBillcompletes, draft cleanup is deferred viaInteractionManager.runAfterInteractions(() => removeDraftTransaction(...)). If the user starts a new split before this fires, the old draft persists.Tab navigator skip (
OnyxTabNavigator.tsx:195-202): When the persisted tab in Onyx matches the current tab,onTabSelectedis not called on mount, soresetIOUTypeIfChangeddoesn't fire.useFocusEffectguard (IOURequestStartPage.tsx:237):transaction?.reportID === reportIDcauses early return when starting a new split from the same room — preventing re-initialization.Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR,@MelvinBot <your feedback>to refine this analysis, or explain why you are rejecting Melvin's proposal.melvin-bot commentedon Apr 14, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @ZhenjaHorbach (
External)[-]Expense - Map expense is shown instead scan expense.[/-][+][$250] Expense - Map expense is shown instead scan expense.[/+]49 remaining items
[-][Due for payment 2026-05-07] [$250] Expense - Map expense is shown instead scan expense.[/-][+][Due for payment 2026-05-07] [$500] Expense - Map expense is shown instead scan expense.[/+]melvin-bot commentedon May 5, 2026
Upwork job price has been updated to $500
melvin-bot commentedon May 6, 2026
Triggered auto assignment to @mallenexpensify (
Awaiting Payment)ZhenjaHorbach commentedon May 7, 2026
BugZero Checklist:
Unfortunately, I did not find a suitable PR
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: NA
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
Regression Test Proposal
Test:
Do we agree 👍 or 👎
Zapier Logs
Run ID: 00040eee-7130-a2ac-4c91-8d7a5c693c94melvin-bot commentedon May 7, 2026
Payment Summary
Upwork Job
BugZero Checklist (@mallenexpensify)
mallenexpensify commentedon May 8, 2026
Payment Summary
Contributor: @TaduJR paid $500 via Upwork
Contributor+: @ZhenjaHorbach due $500 via NewDot
@TaduJR can you please accept the job below? Please reply here and tag me once you have.
https://www.upwork.com/jobs/~022044069303414836894
^ Test case created
TaduJR commentedon May 8, 2026
Offer Accepted @mallenexpensify
Thanks!
mallenexpensify commentedon May 8, 2026
@TaduJR paid, summary updated above. Thx.
garrettmknight commentedon May 10, 2026
$500 approved for @ZhenjaHorbach