Repository navigation
[$250] App stuck displaying WS chat pg in loop on tapping back button after deleting reports #82373
Description
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Version Number: 9.3.18-2
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: Exploratory around #81741
Email or phone of affected tester (no customers): kiatest.80+ck2122612@gmail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: iPhone 16/iOS 18.7.1, Pixel 8a/Android 16
App Component: Money Requests
Action Performed:
- Open Hybrid app
- Join as new user with gmail account (Select Somthing else during onboarding)
- Go to Self DM & create a manual expense
- Open the expense >> Tap More >> Duplicate option
- Go to Reports
6.Open the second expense - Select Report field >> Upgrade >> Confirm >> Got it, thanks
- Tap create new report
- Open the second expense
- Tap From link
- Tap + icon >> create new report (This is an optional step)
- Delete both report(s) via contextual menu (or delete it from expense details page)
- Tap back button & observe workspace chat page is displayed
- Repeat step 13 few more times & observe workspace chat page displayed in loop
- Swipe page to right using swipe gesture - observe not here page appears & return to WS chat page
Expected Result:
App should not stuck in workspace chat page & user should be redirected to Inbox after deleting reports
Actual Result:
App get stuck displaying same workspace chat page in loop on tapping back button after deleting reports
Workaround:
Unknown
Platforms:
- Android: App
- Android: mWeb Chrome
- iOS: App
- iOS: mWeb Safari
- iOS: mWeb Chrome
- Windows: Chrome
- MacOS: Chrome / Safari
Screenshots/Videos
1.mp4
Issue Owner
Current Issue Owner: @aimane-chnaifUpwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~022028954394778650882
- Upwork Job ID: 2028954394778650882
- Last Price Increase: 2026-03-24
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
melvin-bot commentedon Mar 3, 2026
Triggered auto assignment to @CortneyOfstad (
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 3, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
After deleting expense reports in a workspace, pressing the back button gets stuck in a loop displaying the same workspace chat page repeatedly. The user cannot escape to the Inbox. Swiping right briefly shows a "not here" page before returning to the workspace chat.
What is the root cause of that problem?
When expense reports are deleted, only the Onyx data is cleared — the navigation stack inside the
ReportsSplitNavigatoris not cleaned up. The orphaned report screen entries remain in the stack.When the user presses back and lands on one of these stale entries,
ReportScreendetects the missing report data and redirects to the parent workspace chat usingNavigation.navigate(). Critically,Navigation.navigate()is converted to a PUSH action bylinkTowhen the target reportID differs from the currently focused one. This adds a new workspace chat entry on top of the stack instead of replacing the stale entry.The result: pressing back pops the new workspace chat entry, revealing the next stale deleted report underneath, which triggers another redirect+push, creating an infinite loop.
Specifically, two independent
useEffecthooks inReportScreen.tsxboth detect deletion and redirect viaNavigation.navigate():isRemovalExpectedForReportType(coversisMoneyRequestReport), callsNavigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(prevReport.parentReportID))at line 759useReportWasDeletedhook, callsNavigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(deletedReportParentID))at line 810Both push new entries rather than cleaning up the stale ones.
A
Navigation.removeReportScreen()function exists atNavigation.ts:815-831that can filter report screens from the navigation state, but it is only called fromuseSelectedTransactionsActions.ts:150(bulk transaction delete in search) — it is never called during the regular report deletion flow (deleteAppReport/deleteReport).What changes do you think we should make in order to solve the problem?
The redirect navigation in
ReportScreenwhen a report is detected as deleted should not push a new entry. Instead, it should clean up the stale navigation entries. Two approaches:Call
Navigation.removeReportScreen()for the deleted reportID(s) in the deletion flow (insidedeleteAppReportor in theReportScreenuseEffect before navigating). This would remove the orphaned entries from the SplitNavigator stack. Note:removeReportScreencurrently dispatches against the root navigator state and may need to be updated to reach into the nested SplitNavigator state.Use
REPLACEinstead ofPUSHfor the redirect navigation inReportScreenwhen handling deleted reports. TheNavigation.navigate()calls at lines 759 and 810 could pass a flag (e.g.,forceReplace: true) solinkTousesREPLACEinstead of converting toPUSH. This prevents the stack from growing but doesn't remove the stale entries underneath — it would still require multiple back presses to escape if many reports were deleted.Recommended: Option 1 is the more complete fix. When a report is deleted and
ReportScreendetects it, callNavigation.removeReportScreen(new Set([reportIDFromRoute]))before navigating to the parent. This mirrors whatuseSelectedTransactionsActionsalready does for bulk deletes.What alternative solutions did you explore? (Optional)
popToSidebar()unconditionally before redirecting: This would work but is too aggressive — it clears the entire stack including legitimate entries the user may want to navigate back to.deleteReport()/deleteAppReport(): This would require passing navigation context into data-layer functions, which violates the current separation of concerns. The cleanup is better placed inReportScreenwhere the stale state is detected.Detailed Investigation
Root Cause Analysis
The navigation architecture uses a
ReportsSplitNavigatorwith a stack:[INBOX, REPORT(chat), REPORT(expense1), REPORT(expense2), ...]. When expense reports are deleted:deleteReport()atsrc/libs/actions/Report/index.ts:3688-3725nullifies Onyx data but does nothing to the navigation statedeleteAppReport()atsrc/libs/actions/Report/index.ts:5400+marks reports as pending deletion optimistically, then nulls on API success — also no nav cleanupREPORTentries remain in the SplitNavigator stackWhen
ReportScreenrenders for a stale entry:useReportWasDeleted(atsrc/pages/inbox/hooks/useReportWasDeleted.ts) detects the report data is goneNavigation.navigate()to the parent (workspace chat)linkToatsrc/libs/Navigation/helpers/linkTo/index.ts:154-161converts this to PUSH because the target reportID differs from the current focused routeEvidence Chain
[INBOX] → [REPORT(ws-chat)] → [REPORT(expense1)] → [REPORT(expense2)]REPORT(ws-chat)→ stack:[INBOX, REPORT(ws-chat), REPORT(expense1-stale), REPORT(expense2-stale), REPORT(ws-chat-new)]Relevant Code
src/pages/inbox/ReportScreen.tsx:700-768— Report removal detection and redirectsrc/pages/inbox/ReportScreen.tsx:797-819— useReportWasDeleted redirectsrc/libs/Navigation/helpers/linkTo/index.ts:154-161— NAVIGATE→PUSH conversionsrc/libs/Navigation/Navigation.ts:815-831— removeReportScreen (exists but unused in this flow)src/libs/actions/Report/index.ts:3688-3725— deleteReport (Onyx-only, no nav cleanup)src/hooks/useSelectedTransactionsActions.ts:150— Only place removeReportScreen is calledImplementation Notes
removeReportScreendispatches against the root navigator state but report screens are nested insideReportsSplitNavigator. The function may need to be updated to traverse into nested navigator states.isFocusedguard prevents non-focused stale screens from redirecting immediately, but they become focused when the user navigates back to them.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 3, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @aimane-chnaif (
External)[-]App stuck displaying WS chat pg in loop on tapping back button after deleting reports[/-][+][$250] App stuck displaying WS chat pg in loop on tapping back button after deleting reports[/+]melvin-bot commentedon Mar 3, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022028954394778650882
melvin-bot commentedon Mar 9, 2026
@aimane-chnaif Eep! 4 days overdue now. Issues have feelings too...
38 remaining items
m-natarajan commentedon Apr 8, 2026
Not reproducible on build v9.3.54-3 on iPhone 16/18.7.1
ScreenRecording_04-08-2026.12-51-27_1.MP4
aimane-chnaif commentedon Apr 8, 2026
@MelvinBot which recent PR fixed this?
MelvinBot commentedon Apr 8, 2026
There's no single PR that directly targeted this issue, but several related PRs merged between v9.3.18 and v9.3.54 likely fixed it collectively. The most relevant candidates:
fix: filter deleted reports from navigation and disable in search list #85292 — "Filter deleted reports from navigation and disable in search list" (
TaduJR, merged Mar 25). AddsisReportPendingDeletefiltering so deleted reports are excluded from navigation sections, preventing the infinite-loading/redirect loop when landing on a deleted report.Fix Not Here page after removing split expense #84656 — "Fix Not Here page after removing split expense" (
MelvinBot, merged Mar 13). Fixes navigation to a deleted expense report after removing splits.Fix 'Not Found' page flash after deleting expense #83613 — "Fix 'Not Found' page flash after deleting expense" (
MelvinBot, merged Mar 2). DefersdeleteTransaction()until after the RHP close animation to prevent stale navigation state.Use backward navigation pattern for reverse-split deletion #85425 — "Use backward navigation pattern for reverse-split deletion" (
MelvinBot, merged Mar 24). Fixes back navigation after reverse-split report deletion.Navigate to Home instead of Inbox from NotFoundPage #85526 — "Navigate to Home instead of Inbox from NotFoundPage" (merged Mar 19). Changes where not-found pages redirect to.
Note: QA also reported that step 4 of the reproduction (duplicating a tracked expense) itself fails on v9.3.54-2, so the original reproduction path may no longer be valid regardless of the navigation fix.
melvin-bot commentedon Apr 13, 2026
@aimane-chnaif Huh... This is 4 days overdue. Who can take care of this?
CortneyOfstad commentedon Apr 14, 2026
@aimane-chnaif any update based on Melvin's response above?
aimane-chnaif commentedon Apr 14, 2026
@CortneyOfstad let's close this as not reproducible
melvin-bot commentedon Apr 17, 2026
@aimane-chnaif Whoops! This issue is 2 days overdue. Let's get this updated quick!
mvtglobally commentedon Apr 18, 2026
Issue not reproducible during KI retests. (First week)