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
Expense - Workspace selector opens after selecting default workspace and choosing category #94551
Version Number: 9.4.19-1 Reproducible in staging?: Yes Reproducible in production?: N/A - new feature, doesn't exist in prod If this was caught during regression testing, add the test name, ID and link from BrowserStack:#93402 Email or phone of affected tester (no customers):jnsodijosdnjosjio@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Mac 26.5 / Chrome App Component: Money Requests
Action Performed:
Precondition:
Create two workspaces.
Set personal policy as default policy on OD.
Go to staging.new.expensify.com
Go to self DM.
Create an expense.
Open the expense.
Click Category.
Select any workspace.
Choose any category.
Expected Result:
RHP will close.
Actual Result:
Workspace selector opens after selecting default workspace and choosing category.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
Confidence: High — root cause is deterministic from the code and matches the diff of the suspected PR (#93402).
What is the root cause of that problem?
PR #93402 migrated the Category step to the new "dynamic route" system, but in the workspace‑selector branch of MoneyRequestView's Category onPress, the explicit backTo route (the original expense RHP) was dropped.
In src/components/ReportActionItem/MoneyRequestView.tsx:1262-1274, the !policy && shouldSelectPolicy branch calls createDynamicRoute(MONEY_REQUEST_STEP_CATEGORY.getRoute(...))without passing a basePath. When no basePath is supplied, createDynamicRoute falls back to Navigation.getActiveRoute(), so the category route gets anchored to the workspace‑selector context instead of the expense RHP. After a category is chosen, the page computes its back target with useDynamicBackPath (which just strips the category suffix), so goBack lands the user back on the workspace selector → the loop.
The analogous, non‑migrated distance‑rate branch right above it still does this correctly — it threads Navigation.getActiveRoute() as the backTo (MoneyRequestView.tsx:948-961) — which is exactly the argument the category branch lost.
Evidence / data flow
Self‑DM expense RHP open → user taps Category.
With multiple workspaces + personal default policy, shouldSelectPolicy is true → the !policy && shouldSelectPolicy branch runs and navigates to SET_DEFAULT_WORKSPACE with navigateTo = a dynamic category route whose base was captured from the current active route (no explicit RHP backTo).
User selects a workspace → SetDefaultWorkspacePage does Navigation.navigate(navigateTo) → opens the category page anchored to the wrong base.
User picks a category → updateCategory/navigateBack → Navigation.goBack(backPath) where backPath comes from useDynamicBackPath (suffix stripped off the wrongly‑anchored base) → returns to the workspace selector instead of dismissing the RHP.
Old code (removed in the PR) passed Navigation.getActiveRoute() as an explicit backTo into the category route, so goBack dismissed the RHP correctly.
What changes do you think we should make in order to solve the problem?
In the !policy && shouldSelectPolicy branch at MoneyRequestView.tsx:1262-1274, pass the original expense RHP route as the explicit basePath (second argument) to createDynamicRoute, mirroring the distance‑rate branch and the other category branches in the same file. getReportRHPActiveRoute() is already available in this component (from useActiveRoute() at line 202 and used elsewhere, e.g. lines 898/910/970). This makes useDynamicBackPath strip the category suffix and return to the expense RHP (dismissing it) instead of the workspace selector.
The same latent pattern should be double‑checked in the other migrated selector branches (tax rate / tax amount / attendee) that also rely on createDynamicRoute's implicit basePath when reached through an intermediate selector screen.
What alternative solutions did you explore? (Optional)
Reverting #93402 would also fix it, but a targeted fix (restoring the explicit basePath) is preferable for a deploy blocker since the rest of the migration is working.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/94551) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
Activity
applause-bot commentedon Jun 25, 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/828b3d9280639ab6edaa820cb335a0fdbd9f0890c3104caad1eeb1a46e759b5a
melvin-bot commentedon Jun 25, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #93402
melvin-bot commentedon Jun 25, 2026
💬 A slack conversation has been started in #expensify-open-source
github-actions commentedon Jun 25, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
MelvinBot commentedon Jun 25, 2026
Proposal
What is the root cause of that problem?
PR #93402 migrated the Category step to the new "dynamic route" system, but in the workspace‑selector branch of
MoneyRequestView's CategoryonPress, the explicitbackToroute (the original expense RHP) was dropped.In
src/components/ReportActionItem/MoneyRequestView.tsx:1262-1274, the!policy && shouldSelectPolicybranch callscreateDynamicRoute(MONEY_REQUEST_STEP_CATEGORY.getRoute(...))without passing a basePath. When no basePath is supplied,createDynamicRoutefalls back toNavigation.getActiveRoute(), so the category route gets anchored to the workspace‑selector context instead of the expense RHP. After a category is chosen, the page computes its back target withuseDynamicBackPath(which just strips the category suffix), sogoBacklands the user back on the workspace selector → the loop.The analogous, non‑migrated distance‑rate branch right above it still does this correctly — it threads
Navigation.getActiveRoute()as thebackTo(MoneyRequestView.tsx:948-961) — which is exactly the argument the category branch lost.Evidence / data flow
shouldSelectPolicyis true → the!policy && shouldSelectPolicybranch runs and navigates toSET_DEFAULT_WORKSPACEwithnavigateTo= a dynamic category route whose base was captured from the current active route (no explicit RHPbackTo).SetDefaultWorkspacePagedoesNavigation.navigate(navigateTo)→ opens the category page anchored to the wrong base.updateCategory/navigateBack→Navigation.goBack(backPath)wherebackPathcomes fromuseDynamicBackPath(suffix stripped off the wrongly‑anchored base) → returns to the workspace selector instead of dismissing the RHP.Old code (removed in the PR) passed
Navigation.getActiveRoute()as an explicitbackTointo the category route, sogoBackdismissed the RHP correctly.What changes do you think we should make in order to solve the problem?
In the
!policy && shouldSelectPolicybranch atMoneyRequestView.tsx:1262-1274, pass the original expense RHP route as the explicitbasePath(second argument) tocreateDynamicRoute, mirroring the distance‑rate branch and the other category branches in the same file.getReportRHPActiveRoute()is already available in this component (fromuseActiveRoute()at line 202 and used elsewhere, e.g. lines 898/910/970). This makesuseDynamicBackPathstrip the category suffix and return to the expense RHP (dismissing it) instead of the workspace selector.The same latent pattern should be double‑checked in the other migrated selector branches (tax rate / tax amount / attendee) that also rely on
createDynamicRoute's implicit basePath when reached through an intermediate selector screen.What alternative solutions did you explore? (Optional)
Reverting #93402 would also fix it, but a targeted fix (restoring the explicit basePath) is preferable for a deploy blocker since the rest of the migration is working.
Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/94551)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
m-natarajan commentedon Jun 25, 2026
Not repro, Chrome / v9.4.19-3 (Pending validation in iOS and Android)
REC-20260625173905.mp4
m-natarajan commentedon Jun 25, 2026
Xiaomi Redmi Note 10 / Android 12
app 9.4.19-3
Not repro
Screenrecorder-2026-06-25-18-41-28-878.mp4