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
Create expense opens when navigate back from referral page #100645
Version Number: 9.4.74-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:#99947 Email or phone of affected tester (no customers):applausetester+gm1038529@applause.expensifail.com Issue reported by: Applause Internal Team Bug source: Pull Request QA execution Device used: windows 10/chrome App Component: Other
Action Performed:
Go to staging.new.expensify.com
Open FAB > Create expense > Manual.
Click To.
Click Referral banner at the bottom.
Click RHP back button.
Expected Result:
The previous page, which is Participant list will open.
In the new manual expense flow the participant list is not a page — it's a right-docked modal rendered inside the "Create expense" screen, driven by React state (ParticipantPicker/index.tsx:23-33). Because it has no route, going back from the referral page can only ever land on "Create expense". The back button itself is correct.
Expensify/App#99947 already anticipated this and added a mitigation: close the picker before navigating to the referral page, then reopen it when the screen refocuses. That reopen never runs. Its guard bails out first:
hasSelectedParticipants is always true on this path, because the same component auto-assigns a default recipient (default workspace expense chat, or self DM) with selected: true on mount (IOURequestStepConfirmation.tsx:524-545). So the guard throws the reopen away and the user sees the expense form.
That auto-assignment is also why the reporter had to click "To" (the picker didn't auto-open) — the very state that forces step 3 of the repro is the state that kills the restore.
What changes do you think we should make in order to solve the problem?
Drop the hasSelectedParticipants condition from the focus-listener guard at IOURequestStepConfirmation.tsx:399-409, keeping only the activeTransactionID null check, and remove it from the effect's dependency array.
The stated purpose of that condition — stopping an unrelated RHP round trip from slamming the picker open — is already served by shouldReopenParticipantPickerOnFocusRef on the line above it. That ref is set in exactly one place, closeParticipantPickerForReferralNavigation, and only when the picker was actually visible, so unrelated refocuses already return early. The recipient check is redundant and unconditionally true, which is what makes the code unreachable.
The existing regression test passes only because its fixture seeds participants: [] with no default policy or self DM in Onyx (IOURequestStepConfirmationPageTest.tsx:1537-1574), so it never covers an account with a default workspace — the common production case. Add a case with a default recipient present.
What alternative solutions did you explore? (Optional)
Making the participant picker its own route again, so back works structurally instead of via a state-restore hack. This area has regressed three times in a row on the same design (Expensify/App#87920 converted the route to a modal, Expensify/App#94546 added a partial close-before-navigate, Expensify/App#99947 added the reopen, and now this issue). Worth considering separately, but it is far larger than this fix needs to be.
Investigation details
Full chain
FAB > Create expense > Manual → one route, MONEY_REQUEST.CREATE → IOURequestStartPage.tsx:224 embeds the confirmation step inline.
On mount the default recipient is written into the draft with selected: true, so hasSelectedParticipants (line 347) is true and auto-open is suppressed.
Clicking "To" only flips local state — MoneyRequestConfirmationList.tsx:441-453 calls onOpenParticipantPicker() when the beta is on, versus a real Navigation.navigate(...STEP_PARTICIPANTS) when it's off. No route, no history entry.
Back → DynamicReferralDetailsPage.tsx:68-70 pops correctly to Create expense; the focus listener fires, consumes the ref, then returns at line 404. Picker stays closed.
Ruled out
Stack collapse. The referral page lives in a different modal stack (RIGHT_MODAL.REFERRAL), but it's pushed above an intact money-request stack. Confirmed by the symptom itself: back lands on Create expense, not the Inbox, so the screen survived and its state is intact.
goBack target wrong.useDynamicBackPath correctly strips the referral/:contentType suffix. There is no participant route to target.
Mitigation not deployed.Expensify/App#99947 deployed to staging as 9.4.74-0 about two hours before this was filed, which is the version reported.
Runtime repro
An automated web run reproduced steps 1–3 (Create expense > Manual, participant list, referral banner opens). Step 4 was inconclusive: that test account had no default workspace, so the picker auto-opened rather than needing a "To" click — a different state from the report — and the run then navigated off the app entirely. The code chain above is verified statically; the focus event firing on return was not observed at runtime.
Related issues: a quick scan of open Expensify/App issues for this symptom found no duplicates. The three prior PRs listed under alternatives are the relevant history.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/100645) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
Activity
applause-bot commentedon Sep 8, 2026
While Applause doesn't embed attachments for this bug, here are the links for quick view:
https://platform.applause.com/services/links/v1/external/e0b4c8bc0898ffbf04c78499d905f2341854451ff3d97a21e774f9838e3c6778
MelvinBot commentedon Sep 8, 2026
Proposal
What is the root cause of that problem?
In the new manual expense flow the participant list is not a page — it's a right-docked modal rendered inside the "Create expense" screen, driven by React state (
ParticipantPicker/index.tsx:23-33). Because it has no route, going back from the referral page can only ever land on "Create expense". The back button itself is correct.Expensify/App#99947already anticipated this and added a mitigation: close the picker before navigating to the referral page, then reopen it when the screen refocuses. That reopen never runs. Its guard bails out first:IOURequestStepConfirmation.tsx:404hasSelectedParticipantsis always true on this path, because the same component auto-assigns a default recipient (default workspace expense chat, or self DM) withselected: trueon mount (IOURequestStepConfirmation.tsx:524-545). So the guard throws the reopen away and the user sees the expense form.That auto-assignment is also why the reporter had to click "To" (the picker didn't auto-open) — the very state that forces step 3 of the repro is the state that kills the restore.
What changes do you think we should make in order to solve the problem?
Drop the
hasSelectedParticipantscondition from the focus-listener guard atIOURequestStepConfirmation.tsx:399-409, keeping only theactiveTransactionIDnull check, and remove it from the effect's dependency array.The stated purpose of that condition — stopping an unrelated RHP round trip from slamming the picker open — is already served by
shouldReopenParticipantPickerOnFocusRefon the line above it. That ref is set in exactly one place,closeParticipantPickerForReferralNavigation, and only when the picker was actually visible, so unrelated refocuses already return early. The recipient check is redundant and unconditionally true, which is what makes the code unreachable.The existing regression test passes only because its fixture seeds
participants: []with no default policy or self DM in Onyx (IOURequestStepConfirmationPageTest.tsx:1537-1574), so it never covers an account with a default workspace — the common production case. Add a case with a default recipient present.What alternative solutions did you explore? (Optional)
Making the participant picker its own route again, so back works structurally instead of via a state-restore hack. This area has regressed three times in a row on the same design (
Expensify/App#87920converted the route to a modal,Expensify/App#94546added a partial close-before-navigate,Expensify/App#99947added the reopen, and now this issue). Worth considering separately, but it is far larger than this fix needs to be.Investigation details
Full chain
MONEY_REQUEST.CREATE→IOURequestStartPage.tsx:224embeds the confirmation step inline.selected: true, sohasSelectedParticipants(line 347) is true and auto-open is suppressed.MoneyRequestConfirmationList.tsx:441-453callsonOpenParticipantPicker()when the beta is on, versus a realNavigation.navigate(...STEP_PARTICIPANTS)when it's off. No route, no history entry.ParticipantSelectorFooter.tsx:62-68→ReferralProgramCTA.tsx:66-69) closes the picker, then pushes the referral RHP withbackTo= the Create expense path, sincegetActiveRouteWithoutParams()cannot see a modal.DynamicReferralDetailsPage.tsx:68-70pops correctly to Create expense; the focus listener fires, consumes the ref, then returns at line 404. Picker stays closed.Ruled out
RIGHT_MODAL.REFERRAL), but it's pushed above an intact money-request stack. Confirmed by the symptom itself: back lands on Create expense, not the Inbox, so the screen survived and its state is intact.useDynamicBackPathcorrectly strips thereferral/:contentTypesuffix. There is no participant route to target.Expensify/App#99947deployed to staging as 9.4.74-0 about two hours before this was filed, which is the version reported.Runtime repro
An automated web run reproduced steps 1–3 (Create expense > Manual, participant list, referral banner opens). Step 4 was inconclusive: that test account had no default workspace, so the picker auto-opened rather than needing a "To" click — a different state from the report — and the run then navigated off the app entirely. The code chain above is verified statically; the focus event firing on return was not observed at runtime.
Related issues: a quick scan of open
Expensify/Appissues for this symptom found no duplicates. The three prior PRs listed under alternatives are the relevant history.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/100645)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
view run · no recording available
melvin-bot commentedon Sep 8, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @bernhardoj (
External)melvin-bot commentedon Sep 8, 2026
Unable to auto-create job on Upwork. The BZ team member should create it manually for this issue.
bernhardoj commentedon Sep 9, 2026
I think @thelullabyy should handle this as this is coming from their recent PR
mountiny commentedon Sep 9, 2026
@thelullabyy can you follow up as a regression please
melvin-bot commentedon Sep 14, 2026
@thelullabyy Eep! 4 days overdue now. Issues have feelings too...
23 remaining items
melvin-bot commentedon Nov 3, 2026
@thelullabyy Eep! 4 days overdue now. Issues have feelings too...
melvin-bot commentedon Nov 3, 2026
@thelullabyy Huh... This is 4 days overdue. Who can take care of this?
melvin-bot commentedon Nov 3, 2026
@thelullabyy Eep! 4 days overdue now. Issues have feelings too...
melvin-bot commentedon Nov 4, 2026
@thelullabyy Eep! 4 days overdue now. Issues have feelings too...
melvin-bot commentedon Nov 5, 2026
@thelullabyy 6 days overdue. This is scarier than being forced to listen to Vogon poetry!
jeffrey-graham commentedon Nov 7, 2026
melvin-bot commentedon Nov 7, 2026
thelullabyy commentedon Nov 9, 2026
Finally, I can back to this issue. Will check it today
thelullabyy commentedon Nov 10, 2026
The issue is no longer reproducible. I think we can close this issue cc @ikevin127 @mountiny
Screen.Recording.2026-11-10.at.19.40.19.mov