Skip to content

Chat - Compose box not displayed after logging in via chat link #89028

Closed

Description

@mitarachim

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.62-5
Reproducible in staging?: Yes
Reproducible in production?: No
If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://test-management.browserstack.com/projects/2219752/test-runs/TR-22587/folder/13176964/41237742/1371131085
Email or phone of affected tester (no customers): applausetester+abr2hb@applause.expensifail.com
Issue reported by: Applause Internal Team
Bug source: Regression TC Execution
Device used: Android/IOS
App Component: Other

Action Performed:

  1. Log in in the app
  2. Copy a conversation/chat link in the note
  3. Log out from the app.
  4. Open a conversation/chat link in step 2.
  5. Log in to the app with same account in step 1 .
  6. Observe the chat screen.

Expected Result:

The compose box should be visible, allowing the user to send messages after logging in via the chat link.

Actual Result:

The compose box is not displayed after logging in via the chat link.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari

Screenshots/Videos

Bug7139458_1777311013536.WhatsApp_Video_2026-04-27_at_19.17.49.mp4

View all open jobs on GitHub

Activity

  1. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    DeployBlockerIndicates it should block deploying the API
    on Apr 28, 2026
  2. melvin-bot commented on Apr 28, 2026

    @melvin-bot

    Triggered auto assignment to @deetergp (DeployBlockerCash), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.

  3. melvin-bot commented on Apr 28, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  4. github-actions commented on Apr 28, 2026

    @github-actions
    Contributor

    👋 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:

    1. Identify the pull request that introduced this issue and revert it.
    2. Find someone who can quickly fix the issue.
    3. Fix the issue yourself.
  5. OSBotify commented on Apr 28, 2026

    @OSBotify
    Contributor

    Investigation Summary

    Classification: Frontend bug
    Causing PR: #88733 - "[CP Staging] fix Deeplink - App is stuck on splash screen when navigating to a public room as anon user" by @situchan (Medium confidence)
    Related Issues: #88653, #88545

    Recommendation: NEEDS INVESTIGATION

    PR #88733 is the most likely candidate, but the exact mechanism by which it suppresses the compose box after login is not conclusively traced. The PR author and reviewers should verify whether reverting or patching #88733 resolves the issue.

    Assigned: @situchan (PR author), @ikevin127 @mollfpr (approving reviewers) from highest-confidence causing PR only
    Labels: Both DeployBlockerCash and DeployBlocker are kept — this is a staging-only regression on a frontend component (App repo), so DeployBlockerCash should remain. DeployBlocker label was already present and is kept pending clarification.

    Detailed Analysis

    Evidence

    Bug description: After logging in via a chat link on Android/iOS native apps, the compose box is not displayed. The user lands on the correct report screen and can see messages, but cannot compose new ones.

    Version affected: 9.3.62-5 (staging only, not reproducible in production 9.3.61-x).

    Primary suspect — PR #88733: This cherry-pick modifies src/DeepLinkHandler.tsx in two ways:

    1. Adds allReports / allReportsMetadata to the Onyx loading check:

      // Before:
      if (isLoadingOnyxValue(sessionMetadata, isSelfTourViewedMetadata)) { return; }
      
      // After:
      if (isLoadingOnyxValue(allReportsMetadata, sessionMetadata, conciergeReportIDMetadata,
                             introSelectedMetadata, isSelfTourViewedMetadata, betasMetadata)) {
          return;
      }
      
    2. Adds allReportsMetadata.status (and four other new metadata statuses) to the useEffect dependency array.

    Why this matters for the login-via-link flow: Before PR #88733, the DeepLinkHandler effect ran when session and self-tour data were ready. After PR #88733, the effect also re-runs whenever allReportsMetadata.status changes. When a user logs in, reports begin loading — allReportsMetadata.status transitions from "not loaded" → "loading" → "loaded". Each transition re-runs the effect, calling Linking.getInitialURL() and potentially openReportFromDeepLink again.

    Critically, PR #88733 does NOT include the initialUrlProcessed guard that was added later in PR #86660. Without that guard, openReportFromDeepLink can be called multiple times after the initial URL has already been processed, creating a race condition in the navigation and post-login state setup.

    Compose box mechanics: On mobile (isSmallScreenWidth = true), ReportFooter renders the compose box only when !shouldHideComposer && shouldShowComposeInput. The shouldShowComposeInput Onyx key defaults to false in ReportFooter. It is set to true by ReportFetchHandler on mount (InteractionManager.runAfterInteractions). If the re-triggered deep link navigation causes a second navigation event that interrupts or races with ReportFetchHandler's mount lifecycle, the setShouldShowComposeInput(true) call could be cancelled (the interactionTask.cancel() in the cleanup) before it fires.

    Relationship to PR #86660: The later main-branch PR #86660 adds comprehensive fixes to DeepLinkHandler.tsx including an initialUrlProcessed ref guard, a Promise.race with timeout (to handle HybridApp bridge timeouts), and a safety-net useEffect for authenticated users. These fixes address the same class of re-invocation issues. PR #88733 (the cherry-pick) only includes the allReportsMetadata change without the protective guards.

    Verification

    Affected file: src/DeepLinkHandler.tsx — confirmed modified by PR #88733.

    Files relevant to compose box:

    • src/pages/inbox/report/ReportFooter.tsx — controls compose box rendering based on shouldShowComposeInput and canPerformWriteAction
    • src/pages/inbox/ReportFetchHandler.tsx — sets shouldShowComposeInput(true) on mount
    • src/libs/actions/Composer.ts — setShouldShowComposeInput implementation
    • src/ONYXKEYS.ts — SHOULD_SHOW_COMPOSE_INPUT key definition

    Chronological order confirms PR #88733 is in the 9.3.62-5 build (entry 149 in the StagingDeployCash chronological list, before entry 163 which is the 9.3.62-5 submodule update).

    Root Cause

    The DeepLinkHandler effect, with allReportsMetadata.status added to its dependency array but without an initialUrlProcessed guard, re-invokes openReportFromDeepLink multiple times as reports load after login. This likely creates a race condition where a second navigation event fires while ReportFetchHandler is setting up, causing the InteractionManager.runAfterInteractions task that calls setShouldShowComposeInput(true) to be cancelled by the cleanup function before it executes. The compose box then renders with shouldShowComposeInput = false and is hidden on mobile.

    The complete fix (including the initialUrlProcessed guard and Promise.race timeout) exists in PR #86660 on main but was not cherry-picked to staging alongside PR #88733.

    Recommended action: Either revert PR #88733 from staging, or cherry-pick the additional protections from PR #86660 (initialUrlProcessed guard + cancellation logic) into a new staging CP. The PR author @situchan and reviewer @ikevin127 are best positioned to advise on the preferred approach.

  6. 35 remaining items

  7. situchan commented on May 20, 2026

    @situchan
    Contributor

    @deetergp the original bug is not reproducible anymore. But while executing repro steps in OP, found this navigation issue:

    1. Log in in the app
    2. Copy a conversation/chat link in the note
    3. Log out from the app.
    4. Open a conversation/chat link in step 2.
    5. Log in to the app with same account in step 1 .
    6. Observe the chat screen.

    In Step 5, I got console error.

    The action 'NAVIGATE' with payload {"name":"TabNavigator","params":{"initial":false,"screen":"ReportsSplitNavigator","params":{"pop":true,"initial":true,"screen":"Report","params":{"reportID":"4147074334554922"},"path":"/r/4147074334554922"},"pop":true},"pop":true} was not handled by any navigator.
    
    Do you have a screen named 'TabNavigator'?
    
    If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
    
    console

    Should we fix this?

  8. MelvinBot commented on May 20, 2026

    @MelvinBot
    Contributor

    Yes, this is worth fixing. It's a real navigation timing bug, not just a cosmetic console warning.

    Root cause: During the deep link login flow, openReportFromDeepLink is called with isAuthenticated = false. It awaits waitForProtectedRoutes(), which resolves when CONCIERGE appears in routeNames. However, TabNavigator is loaded lazily via getComponent, so there's a window where the RootStack has registered the screen name but the TabNavigator component hasn't fully mounted to handle the nested navigation action. The Navigation.navigate() call at Link.ts:353 dispatches a NAVIGATE action targeting TabNavigator during this window, producing the unhandled action error.

    Recommended fix: Add NAVIGATORS.TAB_NAVIGATOR to the PROTECTED_SCREENS check (or add a separate waitForProtectedRoutes check that also verifies TabNavigator is in the navigation state). This ensures waitForProtectedRoutes() doesn't resolve until TabNavigator is actually available to handle the navigation action.

    However, since this is a separate bug from the original compose box issue (and the original is no longer reproducible), I'd recommend filing it as a new issue to keep things clean.

  9. deetergp commented on May 20, 2026

    @deetergp
    Contributor

    @MelvinBot Are there currently any open issues that refer to this bug?

  10. MelvinBot commented on May 20, 2026

    @MelvinBot
    Contributor

    I found a few open issues related to deep link navigation failures during/after login, though none report this exact TabNavigator console error:

    The specific TabNavigator NAVIGATE not handled console error from situchan's comment doesn't have its own dedicated issue yet. If you'd like, I can file a new one for it — reply with @MelvinBot file a new issue for the TabNavigator navigation error and I'll create it.

  11. melvin-bot commented on May 26, 2026

    @melvin-bot

    @deetergp, @mollfpr, @ikevin127, @situchan Huh... This is 4 days overdue. Who can take care of this?

  12. deetergp commented on May 27, 2026

    @deetergp
    Contributor

    @MelvinBot file a new issue for the TabNavigator navigation error

  13. MelvinBot commented on May 27, 2026

    @MelvinBot
    Contributor

    🤖 Filed new issue for the TabNavigator navigation error: #91777

  14. situchan commented on May 27, 2026

    @situchan
    Contributor

    @deetergp Can I get assigned in #91777 since I have context as a reporter?

  15. deetergp commented on May 27, 2026

    @deetergp
    Contributor

    You got it! Add you, @situchan.

  16. deetergp commented on May 28, 2026

    @deetergp
    Contributor

    Since this issue was fixed elsewhere and the error messages are being handled in #91777, I think we can close this one out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.DailyKSv2Engineering

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions