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
[$250] Reports - Going back from a replace receipt flow on a scanned expense returns to camera #82491
Version Number: 9.3.19-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:https://test-management.browserstack.com/projects/2219752/folder/13176933/test-cases/41237717 Email or phone of affected tester (no customers):gatantm+626a@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: iPhone 12 mini, iOS 16.7, Google Pixel 9 Pro, Android 16 App Component: Chat Report View
Action Performed:
Precondition: Scan an expense and wait for it to fail or complete
Tap on Reports and select the expense that was scanned (or the report it's in and then the expense)
Tap on the receipt and the overflow button
Select replace
Take a photo
Tap back or swipe to go the previous screen
Expected Result:
User is back to main Reports screen.
Actual Result:
User is back to the camera screen to replace the receipt.
The navigation history is bugged. Works fine with a non scanned expense
@truph01 this seems pretty niche. If we were to fix it, are there other similar instances we could fix at same time? Feel free to tag melvin to ask or for help.
As you can see, the reproduction steps for this issue are very simple and can occur quite easily. It’s not as niche as the original reproduction steps described in the OP.
Please re-state the problem that we are trying to solve in this issue.
When replacing a receipt on an expense (via Reports → tap receipt → overflow menu → Replace → take photo), pressing back/swiping after capturing the photo returns the user to the camera screen instead of navigating back to the previous screen. This occurs on iOS and Android native apps.
What is the root cause of that problem?
The root cause is that the native navigateBack() function in IOURequestStepScan/index.native.tsx does not pass the backTo parameter to Navigation.goBack(), unlike the web version which correctly does.
Native (index.native.tsx:80-82):
navigateBack → Navigation.goBack() // No backTo — just pops one screen
Web (index.tsx:89-91):
navigateBack → Navigation.goBack(backTo) // Uses backTo — navigates to the correct route
Here's the flow that triggers the bug:
User opens the receipt modal (TransactionReceiptModalContent)
User presses "Replace" — on native this calls Navigation.goBack() to dismiss the receipt modal, then via microtask queue navigates to MONEY_REQUEST_STEP_SCAN with backTo set to Navigation.getActiveRoute() (the receipt modal route)
The scan screen opens in the RHP (MoneyRequestModalStackNavigator)
User captures a photo → updateScanAndNavigate fires → calls navigateBack() → Navigation.goBack()withoutbackTo
Because goBack() is called without backTo, it simply pops the current screen from the navigation stack rather than using goUp(backTo) to navigate to the correct destination. This leaves the user in an incorrect navigation state where pressing back leads them back to the camera screen.
On web, navigateBack() passes backTo to goBack(), which calls goUp(backTo) — this correctly resolves the target route and navigates there, avoiding the issue entirely.
What changes do you think we should make in order to solve the problem?
Update navigateBack() in src/pages/iou/request/step/IOURequestStepScan/index.native.tsx to pass backTo to Navigation.goBack(), matching the web behavior:
This ensures that after taking a replacement photo on native, the navigation correctly goes back to the route stored in backTo (the receipt modal route or the screen the user came from) rather than blindly popping one screen.
The updateScanAndNavigate function (lines 254-272) already has a special case using backTo for when navigation state is lost, but the normal flow path should also use it.
What alternative solutions did you explore? (Optional)
An alternative would be to modify updateScanAndNavigate directly to always use Navigation.goBack(backTo) in its normal flow path (the else branch at line 267), rather than calling navigateBack(). However, since navigateBack is also used for the header back button press (onBackButtonPress={navigateBack} at line 448), fixing navigateBack itself ensures consistent behavior for both the photo capture flow and manual back button presses.
This issue has not been updated in over 15 days. @NicMendonca, @truph01 eroding to Monthly issue.
P.S. Is everyone reading this sure this is really a near-term priority? Be brave: if you disagree, go ahead and close it out. If someone disagrees, they'll reopen it, and if they don't: one less thing to do!
[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.
[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:
[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.
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue:
Regression Test Proposal
Precondition:
Test:
Create two expenses, one of which has a receipt.
Tap Reports and select the expense that has the receipt.
Tap on the receipt and the overflow button.
Select Replace.
Take a photo.
Tap back or swipe to return to the previous screen.
Verify the user navigates back to the correct screen (not the camera screen).
Activity
mallenexpensify commentedon Mar 5, 2026
@truph01 this seems pretty niche. If we were to fix it, are there other similar instances we could fix at same time? Feel free to tag melvin to ask or for help.
truph01 commentedon Mar 5, 2026
@mallenexpensify Yes, the reproduction steps can be simplified as follows:
Observe: The user is taken back to the camera screen to replace the receipt.
truph01 commentedon Mar 5, 2026
As you can see, the reproduction steps for this issue are very simple and can occur quite easily. It’s not as niche as the original reproduction steps described in the OP.
melvin-bot commentedon Mar 5, 2026
Triggered auto assignment to @NicMendonca (
Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.MelvinBot commentedon Mar 5, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
When replacing a receipt on an expense (via Reports → tap receipt → overflow menu → Replace → take photo), pressing back/swiping after capturing the photo returns the user to the camera screen instead of navigating back to the previous screen. This occurs on iOS and Android native apps.
What is the root cause of that problem?
The root cause is that the native
navigateBack()function inIOURequestStepScan/index.native.tsxdoes not pass thebackToparameter toNavigation.goBack(), unlike the web version which correctly does.Native (
index.native.tsx:80-82):Web (
index.tsx:89-91):Here's the flow that triggers the bug:
TransactionReceiptModalContent)Navigation.goBack()to dismiss the receipt modal, then via microtask queue navigates toMONEY_REQUEST_STEP_SCANwithbackToset toNavigation.getActiveRoute()(the receipt modal route)MoneyRequestModalStackNavigator)updateScanAndNavigatefires → callsnavigateBack()→Navigation.goBack()withoutbackToBecause
goBack()is called withoutbackTo, it simply pops the current screen from the navigation stack rather than usinggoUp(backTo)to navigate to the correct destination. This leaves the user in an incorrect navigation state where pressing back leads them back to the camera screen.On web,
navigateBack()passesbackTotogoBack(), which callsgoUp(backTo)— this correctly resolves the target route and navigates there, avoiding the issue entirely.What changes do you think we should make in order to solve the problem?
Update
navigateBack()insrc/pages/iou/request/step/IOURequestStepScan/index.native.tsxto passbackTotoNavigation.goBack(), matching the web behavior:This ensures that after taking a replacement photo on native, the navigation correctly goes back to the route stored in
backTo(the receipt modal route or the screen the user came from) rather than blindly popping one screen.The
updateScanAndNavigatefunction (lines 254-272) already has a special case usingbackTofor when navigation state is lost, but the normal flow path should also use it.What alternative solutions did you explore? (Optional)
An alternative would be to modify
updateScanAndNavigatedirectly to always useNavigation.goBack(backTo)in its normal flow path (theelsebranch at line 267), rather than callingnavigateBack(). However, sincenavigateBackis also used for the header back button press (onBackButtonPress={navigateBack}at line 448), fixingnavigateBackitself ensures consistent behavior for both the photo capture flow and manual back button presses.Relevant Code References
src/pages/iou/request/step/IOURequestStepScan/index.native.tsx:80-82— NativenavigateBackmissingbackTosrc/pages/iou/request/step/IOURequestStepScan/index.tsx:89-91— WebnavigateBackcorrectly usingbackTosrc/pages/iou/request/step/IOURequestStepScan/index.native.tsx:254-272— NativeupdateScanAndNavigatesrc/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx:510-533— Replace button navigation (setsbackTo)Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR, or@MelvinBot <your feedback>to refine this analysis.melvin-bot commentedon Mar 5, 2026
Current assignee @truph01 is eligible for the External assigner, not assigning anyone new.
15 remaining items
melvin-bot commentedon Apr 6, 2026
This issue has not been updated in over 15 days. @NicMendonca, @truph01 eroding to Monthly issue.
P.S. Is everyone reading this sure this is really a near-term priority? Be brave: if you disagree, go ahead and close it out. If someone disagrees, they'll reopen it, and if they don't: one less thing to do!
dominictb commentedon May 1, 2026
@truph01 Are you due payment here?
truph01 commentedon May 1, 2026
@dominictb Yes, since I worked on this as C+.
truph01 commentedon May 1, 2026
BugZero Checklist:
[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.
Link to the comment on the PR: https://github.com/Expensify/App/pull/32764/changes#r3172409680
[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:
[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.
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue:
Regression Test Proposal
Precondition:
Test:
Do we agree 👍 or 👎
Zapier Logs
Run ID: 00040eee-8dfb-a090-65d1-389d8ba010c4mallenexpensify commentedon May 1, 2026
Payment Summary
Contributor+: @truph01 due $250 via NewDot
garrettmknight commentedon May 10, 2026
$250 approved for @truph01