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-10-27] [$175] Android - Concierge opens before onboarding is completed #102956
Version Number: 9.5.2-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:#101558 Email or phone of affected tester (no customers):[email protected] Issue reported by: Applause Internal Team Bug source: Pull Request QA execution Device used: Samsung Galaxy S25 FE / Android 16 App Component: Other
Action Performed:
Go to staging.new.expensify.com/concierge
Log in with new Gmail account.
Expected Result:
Concierge will open after onboarding is completed.
Native keeps the /concierge screen through sign-in. On a native cold start, react-navigation builds its first state from the launch URL. Native loads its screens synchronously, so that state survives sign-in. After sign-up, the signed-in screens rebuild from it with ConciergePage on top. Web loads its screens lazily, which drops that state, so ConciergePage never mounts on web.
ConciergePage never checks onboarding. It opens the Concierge chat with shouldDismissModal: true as soon as report data has loaded. This usually happens before the onboarding flow opens.
HybridApp skips the onboarding guard.OnboardingGuard lets navigation through when isHybridAppOnboardingCompleted !== true. The Concierge navigation is not blocked.
RootStackRouter.ts:143-147: an existing comment says a cold-start /concierge link leaves the stack as [CONCIERGE].
Link.tsopenReportFromDeepLink already holds the link until onboarding finishes. The early navigation comes from ConciergePage, not from this path.
What changes do you think we should make in order to solve the problem?
In ConciergePage, skip the navigation while onboarding is still pending:
Read the raw NVP_ONBOARDING.hasCompletedGuidedSetupFlow value. Do not use hasCompletedGuidedSetupFlowSelector, which treats an empty value as completed.
In the focus effect, return early when the value is false, and add it to the effect's dependencies.
After onboarding, the deep link that openReportFromDeepLink holds opens the Concierge chat through navigateAfterOnboarding. If ConciergePage is still mounted, its effect runs again. The "already on this route" check in Link.ts stops the chat from opening twice.
What alternative solutions did you explore? (Optional)
Fix the root cause in navigation. Add a getInitialURL to linkingConfig that returns null when the user is signed out and the route is not public. This also covers other signed-in-only links opened on a cold start, such as /track-expense. It is riskier. Magic links, /transition, SAML, and connection-complete pages need QA.
Narrow the OnboardingGuard HybridApp bypass so it does not apply while NewDot onboarding is pending. This change affects more flows.
Confidence and verification
Confidence: medium. The evidence comes from reading the code. Nobody has tested this on a device yet. Before a PR, confirm on Android that the root state after sign-up contains CONCIERGE.
On web, the tester confirmed that the onboarding modal blocks the app while onboarding is incomplete. The tester could not open the /concierge URL. Web is not listed as affected.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/102956) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
changed the title [-]Android & iOS - Concierge opens before onboarding is completed[/-][+][$175] Android & iOS - Concierge opens before onboarding is completed[/+]on Oct 5, 2026
Please re-state the problem that we are trying to solve in this issue.
On Android and iOS native platforms, when a new user opens staging.new.expensify.com/concierge while logged out and completes sign-up/sign-in, the Concierge chat opens prematurely before the onboarding flow is completed.
What is the root cause of that problem?
Native retains [CONCIERGE] in the initial route state:
On a native cold start via the /concierge deep link, React Navigation builds its root navigation state from the launch URL. In AppNavigator.native.tsx, screen modules are required synchronously, preserving [CONCIERGE] (ConciergePage) at the top of the stack when transitioning to AuthScreens after authentication.
ConciergePage only checks session.authToken and !isLoadingReportData. As soon as OpenApp settles report data (isLoadingReportData turns false), the focus effect immediately calls navigateToConciergeChat({ shouldDismissModal: true }).
Premature redirection bypasses onboarding:
Calling navigateToConciergeChat with shouldDismissModal: true prematurely navigates to the Concierge chat report and dismisses any modal before the user has completed the onboarding flow (hasCompletedGuidedSetupFlow === false).
Deep link replay in Link.ts is already designed to open after onboarding:
In src/libs/actions/Link.ts:621-643, the deep link handler already captures initialHasCompletedGuidedSetupFlow === false and defers opening the link until onboarding is finished via setDeepLinkToOpenAfterOnboarding(...), which is subsequently replayed by navigateAfterOnboarding. The premature navigation observed in this bug is caused exclusively by the independent useFocusEffect inside ConciergePage.tsx.
What changes do you think we should make in order to solve the problem?
1. Add onboarding completion check to ConciergePage.tsx
In src/pages/ConciergePage.tsx:
Subscribe to ONYXKEYS.NVP_ONBOARDING to derive both isSelfTourViewed and the raw hasCompletedGuidedSetupFlow.
Note: We read the raw onboarding?.hasCompletedGuidedSetupFlow directly instead of hasCompletedGuidedSetupFlowSelector, because hasCompletedGuidedSetupFlowSelector returns true for empty objects ({}) or legacy accounts where the property is not yet defined, whereas false is the explicit signal that a user is actively pending onboarding.
Return early in useFocusEffect if hasCompletedGuidedSetupFlow === false.
Include hasCompletedGuidedSetupFlow in the useCallback dependency array so that if ConciergePage remains focused when onboarding completes, it can cleanly proceed.
Add unit tests in tests/unit/ConciergePageTest.tsx:
Verify that when session.authToken exists, isLoadingReportData is false, and hasCompletedGuidedSetupFlow === false, navigateToConciergeChat is not called.
Verify that when hasCompletedGuidedSetupFlow === true (or undefined for legacy accounts), navigateToConciergeChat is called as expected.
Verify that when hasCompletedGuidedSetupFlow updates from false to true, the focus effect triggers navigation.
What alternative solutions did you explore? (Optional)
Using hasCompletedGuidedSetupFlowSelector:
Rejected. As documented in src/selectors/Onboarding.ts and src/libs/actions/Link.ts:543-545, hasCompletedGuidedSetupFlowSelector returns true for empty objects ({}) which can exist transiently on fresh sign-ups before the server responds. Checking hasCompletedGuidedSetupFlow === false on the raw NVP guarantees that pending onboarding is never falsely evaluated as complete.
Intercepting or blocking navigation in OnboardingGuard:
Rejected. navigateToConciergeChat is a direct action called from components. Intercepting it in router guards increases coupling and risks edge-case regressions across other modals or deeplink handlers. Keeping the guard inside ConciergePage.tsx addresses the root cause directly at the trigger site.
Dropping /concierge route on cold start when logged out:
Rejected. As established in PR Open a deep link captured before onboarding instead of dropping it #101558, the intended product behavior is to preserve deeplinks opened prior to onboarding so the user reaches their destination immediately after completing setup, rather than discarding the route.
Please re-state the problem that we are trying to solve in this issue.
On Android and iOS, a new user who opens /concierge and then signs up sees the Concierge chat open before the onboarding flow is completed.
What is the root cause of that problem?
I agree with the mechanism already laid out on this thread: native preserves [CONCIERGE] in the initial route stack through sign-in (web lazy-loads its screens and drops it), and ConciergePage's focus effect navigates to the Concierge chat as soon as report data has loaded, with no onboarding check at all:
I want to flag a gap in the fix already proposed on this thread (checking the raw NVP_ONBOARDING.hasCompletedGuidedSetupFlow === false), because I think it can still race for exactly the account in this report — a brand-new sign-up.
The existing hasCompletedGuidedSetupFlowSelector has a documented reason for treating an unloaded NVP as "completed" — it literally can't tell "not loaded yet" apart from "already onboarded":
Reading the raw field and checking === false only fixes half of that ambiguity. It correctly stops treating "loaded but legacy/empty" as safe, but it does nothing for the case where NVP_ONBOARDING hasn't synced down from the server at all yet — there, hasCompletedGuidedSetupFlow is undefined, not false, so the proposed guard does not block navigation.
This isn't hypothetical for this bug. The codebase already has a comment acknowledging the server can come back from openApp() with an empty nvp_onboarding even for a user who is genuinely mid-onboarding, which is why a different onboarding-resume path explicitly re-asserts it client-side after the fact:
For the exact repro here — a freshly created account, right after sign-up — NVP_ONBOARDING syncing in after isLoadingReportData has already flipped to false is plausible, not an edge case. If that happens, the proposed fix's guard never triggers, and navigateToConciergeChat still fires early.
The code that actually, correctly decides whether to mount the onboarding modal (AuthScreens.tsx's isOnboardingCompleted === false check) gets its value from useOnboardingFlowRouter, which tracks this exact loading ambiguity separately from the value itself, via the Onyx result's own loading metadata:
ConciergePage's proposed fix doesn't use this metadata at all — it only looks at the resolved value.
What changes do you think we should make in order to solve the problem?
In ConciergePage, read NVP_ONBOARDING with its metadata (useOnyx(ONYXKEYS.NVP_ONBOARDING) returns [value, metadata]), and block navigation while that key is still loading, not just when it has already resolved to hasCompletedGuidedSetupFlow === false:
Block when isLoadingOnyxValue(onboardingMetadata) is true (NVP not synced yet — don't guess).
Block when the resolved value's hasCompletedGuidedSetupFlow === false (onboarding confirmed incomplete).
Otherwise, proceed as today.
This mirrors the same loading-vs-value distinction useOnboardingFlowRouter already relies on to correctly gate the onboarding modal itself, instead of re-deriving a second, less careful check inside ConciergePage.
What alternative solutions did you explore? (Optional)
Checking only the raw hasCompletedGuidedSetupFlow === false value, as already proposed on this thread, fixes the case hasCompletedGuidedSetupFlowSelector itself warns about (empty/legacy onboarding treated as complete), but not the case where the key hasn't loaded at all yet — which the codebase has already had to work around once, in OnboardingFlow.ts's 2FA-resume path. I'd rather reuse the loading-metadata pattern already proven in useOnboardingFlowRouter than add a second place that can be wrong in the same way.
changed the title [-][$175] Android & iOS - Concierge opens before onboarding is completed[/-][+][$175] Android - Concierge opens before onboarding is completed[/+]on Oct 5, 2026
Please re-state the problem that we are trying to solve in this issue.
On Android (and iOS), when a user opens staging.new.expensify.com/concierge while logged out (which opens the native app via deep link) and signs up with a new account, the Concierge chat opens immediately and force-dismisses the onboarding flow before the user can complete onboarding.
ConciergePage force-dismisses the onboarding modal:src/pages/ConciergePage.tsx#L36-L56 only checks !isLoadingReportData and lacks guards for isLoadingApp or onboarding completion. As soon as report data loads, it calls navigateToConciergeChat({ shouldDismissModal: true }), which force-dismisses the active OnboardingModalNavigator and jumps directly into Concierge chat.
Race condition on fresh sign-ups: Checking only hasCompletedGuidedSetupFlow === false fails because NVP_ONBOARDING is initially undefined before OpenApp resolves. ConciergePage must wait for isLoadingApp === false before evaluating onboarding state.
What changes do you think we should make in order to solve the problem?
isLoadingApp !== false (app/session data is still loading from the server)
isLoadingReportData !== false
onboarding?.hasCompletedGuidedSetupFlow === false (user has not completed onboarding)
Add isLoadingApp and hasCompletedGuidedSetupFlow to the useCallback dependency array.
Preserve post-onboarding deep link replay:
Once onboarding completes, navigateAfterOnboarding (src/libs/navigateAfterOnboarding.ts#L120-L122) will automatically replay the parked deep link (deferred via Link.ts / PR #101558) and open Concierge cleanly.
Add unit test coverage in tests/unit/ConciergePageTest.tsx:
Verify that navigateToConciergeChat is not called while isLoadingApp is true.
Verify that navigateToConciergeChat is not called when hasCompletedGuidedSetupFlow === false.
Verify that navigation proceeds once isLoadingApp is false and onboarding is completed (true or legacy accounts).
What alternative solutions did you explore? (Optional)
well, I think even though this is related to #99940, not regression from our PR.
This issue happens on staging even now (after we reverted PR #101558) and bug in #99940 was a bit different from here.
changed the title [-][$175] Android - Concierge opens before onboarding is completed[/-][+][Due for payment 2026-10-27] [$175] Android - Concierge opens before onboarding is completed[/+]on Oct 20, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.14-3 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-27. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
Activity
applause-bot commentedon Oct 5, 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/a00190b2a2ea6dc4fb7d4d44617caeaf74ddcfe5feda70cfb9f45abee3b40c9d
MelvinBot commentedon Oct 5, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android and iOS, a new user who opens
/conciergeand then signs up sees the Concierge chat before onboarding is completed.What is the root cause of that problem?
This bug already exists in production. Open a deep link captured before onboarding instead of dropping it did not cause it.
/conciergescreen through sign-in. On a native cold start, react-navigation builds its first state from the launch URL. Native loads its screens synchronously, so that state survives sign-in. After sign-up, the signed-in screens rebuild from it withConciergePageon top. Web loads its screens lazily, which drops that state, soConciergePagenever mounts on web.ConciergePagenever checks onboarding. It opens the Concierge chat withshouldDismissModal: trueas soon as report data has loaded. This usually happens before the onboarding flow opens.OnboardingGuardlets navigation through whenisHybridAppOnboardingCompleted !== true. The Concierge navigation is not blocked.Code references
AppNavigator.native.tsx:26-32:AuthScreensandPublicScreensload withrequire. Web useslazyinAppNavigator.tsx:9-10.ConciergePage.tsx:35-56: opens the chat onceisLoadingReportDatais false. It has no onboarding check.OnboardingGuard.ts:216: the HybridApp first-transition bypass.RootStackRouter.ts:143-147: an existing comment says a cold-start/conciergelink leaves the stack as[CONCIERGE].Link.tsopenReportFromDeepLinkalready holds the link until onboarding finishes. The early navigation comes fromConciergePage, not from this path.What changes do you think we should make in order to solve the problem?
In
ConciergePage, skip the navigation while onboarding is still pending:NVP_ONBOARDING.hasCompletedGuidedSetupFlowvalue. Do not usehasCompletedGuidedSetupFlowSelector, which treats an empty value as completed.false, and add it to the effect's dependencies.After onboarding, the deep link that
openReportFromDeepLinkholds opens the Concierge chat throughnavigateAfterOnboarding. IfConciergePageis still mounted, its effect runs again. The "already on this route" check inLink.tsstops the chat from opening twice.What alternative solutions did you explore? (Optional)
getInitialURLtolinkingConfigthat returnsnullwhen the user is signed out and the route is not public. This also covers other signed-in-only links opened on a cold start, such as/track-expense. It is riskier. Magic links,/transition, SAML, and connection-complete pages need QA.OnboardingGuardHybridApp bypass so it does not apply while NewDot onboarding is pending. This change affects more flows.Confidence and verification
CONCIERGE./conciergeURL. Web is not listed as affected./conciergeonboarding flow.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/102956)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 Oct 5, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @QichenZhu (
External)[-]Android & iOS - Concierge opens before onboarding is completed[/-][+][$175] Android & iOS - Concierge opens before onboarding is completed[/+]melvin-bot commentedon Oct 5, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022106961523484004173
bonnhatnguyen commentedon Oct 5, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android and iOS native platforms, when a new user opens
staging.new.expensify.com/conciergewhile logged out and completes sign-up/sign-in, the Concierge chat opens prematurely before the onboarding flow is completed.What is the root cause of that problem?
Native retains
[CONCIERGE]in the initial route state:On a native cold start via the
/conciergedeep link, React Navigation builds its root navigation state from the launch URL. InAppNavigator.native.tsx, screen modules are required synchronously, preserving[CONCIERGE](ConciergePage) at the top of the stack when transitioning toAuthScreensafter authentication.ConciergePagelacks an onboarding completion guard:In
src/pages/ConciergePage.tsx:ConciergePageonly checkssession.authTokenand!isLoadingReportData. As soon asOpenAppsettles report data (isLoadingReportDataturnsfalse), the focus effect immediately callsnavigateToConciergeChat({ shouldDismissModal: true }).Premature redirection bypasses onboarding:
Calling
navigateToConciergeChatwithshouldDismissModal: trueprematurely navigates to the Concierge chat report and dismisses any modal before the user has completed the onboarding flow (hasCompletedGuidedSetupFlow === false).Deep link replay in
Link.tsis already designed to open after onboarding:In
src/libs/actions/Link.ts:621-643, the deep link handler already capturesinitialHasCompletedGuidedSetupFlow === falseand defers opening the link until onboarding is finished viasetDeepLinkToOpenAfterOnboarding(...), which is subsequently replayed bynavigateAfterOnboarding. The premature navigation observed in this bug is caused exclusively by the independentuseFocusEffectinsideConciergePage.tsx.What changes do you think we should make in order to solve the problem?
1. Add onboarding completion check to
ConciergePage.tsxIn
src/pages/ConciergePage.tsx:ONYXKEYS.NVP_ONBOARDINGto derive bothisSelfTourViewedand the rawhasCompletedGuidedSetupFlow.onboarding?.hasCompletedGuidedSetupFlowdirectly instead ofhasCompletedGuidedSetupFlowSelector, becausehasCompletedGuidedSetupFlowSelectorreturnstruefor empty objects ({}) or legacy accounts where the property is not yet defined, whereasfalseis the explicit signal that a user is actively pending onboarding.useFocusEffectifhasCompletedGuidedSetupFlow === false.hasCompletedGuidedSetupFlowin theuseCallbackdependency array so that ifConciergePageremains focused when onboarding completes, it can cleanly proceed.2. Unit Test Coverage
Add unit tests in
tests/unit/ConciergePageTest.tsx:session.authTokenexists,isLoadingReportDataisfalse, andhasCompletedGuidedSetupFlow === false,navigateToConciergeChatis not called.hasCompletedGuidedSetupFlow === true(orundefinedfor legacy accounts),navigateToConciergeChatis called as expected.hasCompletedGuidedSetupFlowupdates fromfalsetotrue, the focus effect triggers navigation.What alternative solutions did you explore? (Optional)
Using
hasCompletedGuidedSetupFlowSelector:Rejected. As documented in
src/selectors/Onboarding.tsandsrc/libs/actions/Link.ts:543-545,hasCompletedGuidedSetupFlowSelectorreturnstruefor empty objects ({}) which can exist transiently on fresh sign-ups before the server responds. CheckinghasCompletedGuidedSetupFlow === falseon the raw NVP guarantees that pending onboarding is never falsely evaluated as complete.Intercepting or blocking navigation in
OnboardingGuard:Rejected.
navigateToConciergeChatis a direct action called from components. Intercepting it in router guards increases coupling and risks edge-case regressions across other modals or deeplink handlers. Keeping the guard insideConciergePage.tsxaddresses the root cause directly at the trigger site.Dropping
/conciergeroute on cold start when logged out:Rejected. As established in PR Open a deep link captured before onboarding instead of dropping it #101558, the intended product behavior is to preserve deeplinks opened prior to onboarding so the user reaches their destination immediately after completing setup, rather than discarding the route.
Contributor details
Your Expensify account email: [email protected]
Upwork Profile Link: https://www.upwork.com/freelancers/~0139ed4098bdc50182
melvin-bot commentedon Oct 5, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
amar-sheikh commentedon Oct 5, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android and iOS, a new user who opens
/conciergeand then signs up sees the Concierge chat open before the onboarding flow is completed.What is the root cause of that problem?
I agree with the mechanism already laid out on this thread: native preserves
[CONCIERGE]in the initial route stack through sign-in (web lazy-loads its screens and drops it), andConciergePage's focus effect navigates to the Concierge chat as soon as report data has loaded, with no onboarding check at all:App/src/pages/ConciergePage.tsx
Lines 36 to 57 in d0cf159
I want to flag a gap in the fix already proposed on this thread (checking the raw
NVP_ONBOARDING.hasCompletedGuidedSetupFlow === false), because I think it can still race for exactly the account in this report — a brand-new sign-up.The existing
hasCompletedGuidedSetupFlowSelectorhas a documented reason for treating an unloaded NVP as "completed" — it literally can't tell "not loaded yet" apart from "already onboarded":App/src/selectors/Onboarding.ts
Lines 9 to 29 in d0cf159
Reading the raw field and checking
=== falseonly fixes half of that ambiguity. It correctly stops treating "loaded but legacy/empty" as safe, but it does nothing for the case whereNVP_ONBOARDINGhasn't synced down from the server at all yet — there,hasCompletedGuidedSetupFlowisundefined, notfalse, so the proposed guard does not block navigation.This isn't hypothetical for this bug. The codebase already has a comment acknowledging the server can come back from
openApp()with an emptynvp_onboardingeven for a user who is genuinely mid-onboarding, which is why a different onboarding-resume path explicitly re-asserts it client-side after the fact:App/src/libs/actions/Welcome/OnboardingFlow.ts
Lines 221 to 229 in d0cf159
For the exact repro here — a freshly created account, right after sign-up —
NVP_ONBOARDINGsyncing in afterisLoadingReportDatahas already flipped tofalseis plausible, not an edge case. If that happens, the proposed fix's guard never triggers, andnavigateToConciergeChatstill fires early.The code that actually, correctly decides whether to mount the onboarding modal (
AuthScreens.tsx'sisOnboardingCompleted === falsecheck) gets its value fromuseOnboardingFlowRouter, which tracks this exact loading ambiguity separately from the value itself, via the Onyx result's own loading metadata:App/src/hooks/useOnboardingFlow.ts
Lines 33 to 50 in d0cf159
App/src/types/utils/isLoadingOnyxValue.ts
Lines 1 to 6 in d0cf159
ConciergePage's proposed fix doesn't use this metadata at all — it only looks at the resolved value.What changes do you think we should make in order to solve the problem?
In
ConciergePage, readNVP_ONBOARDINGwith its metadata (useOnyx(ONYXKEYS.NVP_ONBOARDING)returns[value, metadata]), and block navigation while that key is still loading, not just when it has already resolved tohasCompletedGuidedSetupFlow === false:isLoadingOnyxValue(onboardingMetadata)is true (NVP not synced yet — don't guess).hasCompletedGuidedSetupFlow === false(onboarding confirmed incomplete).This mirrors the same loading-vs-value distinction
useOnboardingFlowRouteralready relies on to correctly gate the onboarding modal itself, instead of re-deriving a second, less careful check insideConciergePage.What alternative solutions did you explore? (Optional)
Checking only the raw
hasCompletedGuidedSetupFlow === falsevalue, as already proposed on this thread, fixes the casehasCompletedGuidedSetupFlowSelectoritself warns about (empty/legacy onboarding treated as complete), but not the case where the key hasn't loaded at all yet — which the codebase has already had to work around once, inOnboardingFlow.ts's 2FA-resume path. I'd rather reuse the loading-metadata pattern already proven inuseOnboardingFlowRouterthan add a second place that can be wrong in the same way.[-][$175] Android & iOS - Concierge opens before onboarding is completed[/-][+][$175] Android - Concierge opens before onboarding is completed[/+]kushu7 commentedon Oct 5, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android (and iOS), when a user opens
staging.new.expensify.com/conciergewhile logged out (which opens the native app via deep link) and signs up with a new account, the Concierge chat opens immediately and force-dismisses the onboarding flow before the user can complete onboarding.What is the root cause of that problem?
Native retains
/conciergeon the stack: Openingstaging.new.expensify.com/conciergetriggers the Android App Link intent filter inandroid/app/src/main/AndroidManifest.xml#L108(pathPrefix="/concierge"). Unlike Web, Native loads screens synchronously insrc/libs/Navigation/AppNavigator/AppNavigator.native.tsx#L25-L30and preservesSCREENS.CONCIERGE(src/pages/ConciergePage.tsx) at the top of the stack across authentication.ConciergePageforce-dismisses the onboarding modal:src/pages/ConciergePage.tsx#L36-L56only checks!isLoadingReportDataand lacks guards forisLoadingAppor onboarding completion. As soon as report data loads, it callsnavigateToConciergeChat({ shouldDismissModal: true }), which force-dismisses the activeOnboardingModalNavigatorand jumps directly into Concierge chat.Race condition on fresh sign-ups: Checking only
hasCompletedGuidedSetupFlow === falsefails becauseNVP_ONBOARDINGis initiallyundefinedbeforeOpenAppresolves.ConciergePagemust wait forisLoadingApp === falsebefore evaluating onboarding state.What changes do you think we should make in order to solve the problem?
Update
src/pages/ConciergePage.tsx:ONYXKEYS.IS_LOADING_APPto trackOpenAppinitialization.ONYXKEYS.NVP_ONBOARDINGto readonboarding?.hasCompletedGuidedSetupFlow.useFocusEffect(src/pages/ConciergePage.tsx#L36-L56), block navigation if:isLoadingApp !== false(app/session data is still loading from the server)isLoadingReportData !== falseonboarding?.hasCompletedGuidedSetupFlow === false(user has not completed onboarding)isLoadingAppandhasCompletedGuidedSetupFlowto theuseCallbackdependency array.Preserve post-onboarding deep link replay:
Once onboarding completes,
navigateAfterOnboarding(src/libs/navigateAfterOnboarding.ts#L120-L122) will automatically replay the parked deep link (deferred viaLink.ts/ PR #101558) and open Concierge cleanly.Add unit test coverage in
tests/unit/ConciergePageTest.tsx:navigateToConciergeChatis not called whileisLoadingAppistrue.navigateToConciergeChatis not called whenhasCompletedGuidedSetupFlow === false.isLoadingAppisfalseand onboarding is completed (trueor legacy accounts).What alternative solutions did you explore? (Optional)
None
7 remaining items
mukhrr commentedon Oct 10, 2026
well, I think even though this is related to #99940, not regression from our PR.
This issue happens on staging even now (after we reverted PR #101558) and bug in #99940 was a bit different from here.
The issue (#99940) we were fixing on #101558:
This issue (#102956):
But I beleive it's worth fixing this in new PR which we are going to address other regressions from #101558 cc @pecanoro @eh2077
jponikarchuk commentedon Oct 19, 2026
Deploy Blocker #104391 was identified to be related to the PR #103681 that attempted to fix this issue.
melvin-bot commentedon Oct 19, 2026
If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.
If a regression has occurred and you are the assigned CM follow the instructions here.
If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.
[-][$175] Android - Concierge opens before onboarding is completed[/-][+][Due for payment 2026-10-27] [$175] Android - Concierge opens before onboarding is completed[/+]melvin-bot commentedon Oct 20, 2026
@QichenZhu / @eh2077
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.14-3 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-27. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
melvin-bot commentedon Oct 23, 2026
@QichenZhu Whoops! This issue is 2 days overdue. Let's get this updated quick!