Skip to content

[Due for payment 2026-04-02] [Due for payment 2026-04-01] [RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar #86239

Closed

Description

@nlemma

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.43-0
Reproducible in staging?: Yes
Reproducible in production?: No
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #77636
Email or phone of affected tester (no customers): jiosdjnoisdjniojsdiosi@gmail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Mac 26.2 / Chrome
App Component: Money Requests

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to workspace chat.
  3. Create an expense.
  4. Open the report.
  5. Click Amount.
  6. Edit the amount and save it.
  7. Hover over amount edit system message.
  8. Click 3-dot menu > Leave thread.
  9. Go to Account.

Expected Result:

After leaving system message thread, account avatar will not change to fallback avatar.

Actual Result:

After leaving system message thread, account avatar changes to fallback avatar.
Skeleton loader is shown next to fallback avatar.

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Bug7111847_1774365261283.3.mp4

View all open jobs on GitHub

Issue OwnerCurrent Issue Owner: @mallenexpensify

Activity

  1. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    on Mar 24, 2026
  2. melvin-bot commented on Mar 24, 2026

    @melvin-bot

    You have been assigned to this deploy blocker because you recently merged this PR: #77636

  3. melvin-bot commented on Mar 24, 2026

    @melvin-bot

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

  4. github-actions commented on Mar 24, 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 Mar 24, 2026

    @OSBotify
    Contributor

    🔍 Investigation Summary

    Classification: Frontend bug
    Causing PR: #77636 - "Part 1: Remove Onyx.connect() for the key: ONYXKEYS.PERSONAL_DETAILS_LIST in src/libs/actions/Report.ts" by @lorretheboy (High confidence)
    Related Issues: None

    Recommendation: REVERT

    PR #77636 should be reverted to restore the correct behavior. The PR refactored openReport to require a personalDetails parameter but failed to update all call sites, causing the avatar to display as a fallback after leaving a thread.

    Labels: No label changes needed. This is a frontend bug caused by an App PR, so DeployBlockerCash should remain.

    📋 Detailed Analysis

    Evidence

    PR #77636 modified the openReport function to accept a personalDetails parameter (line 1309 in src/libs/actions/Report/index.ts). This parameter is optional in the type definition but critical for properly displaying user avatars.

    The PR updated most call sites to pass personalDetails, but missed two critical locations in src/pages/inbox/ReportScreen.tsx:

    1. Line 567: openReport({reportID: reportIDFromRoute, introSelected, reportActionID: reportActionIDFromRoute, betas});
    2. Line 704: openReport({reportID, introSelected, betas});

    Both calls are missing the personalDetails parameter.

    Verification

    I confirmed that:

    1. PR Part 1: Remove Onyx.connect() for the key: ONYXKEYS.PERSONAL_DETAILS_LIST in src/libs/actions/Report.ts #77636 modified the openReport function signature to include personalDetails as a parameter
    2. src/pages/inbox/ReportScreen.tsx does NOT retrieve or use personalDetails from Onyx
    3. Line 704 is specifically triggered when a user returns to a thread after leaving it (see comment at line 699)
    4. Without personalDetails, the openReport function cannot properly look up user avatar information, resulting in the fallback avatar being displayed
    5. The bug is staging-only, matching the timeline when PR Part 1: Remove Onyx.connect() for the key: ONYXKEYS.PERSONAL_DETAILS_LIST in src/libs/actions/Report.ts #77636 was merged to staging

    Root Cause

    When a user leaves a thread and then navigates to another page (like Account), the ReportScreen component calls openReport without passing personalDetails. This causes the report to be opened without the necessary personal details data, which results in:

    • Avatar data being unavailable or stale
    • The avatar displaying as a fallback/default avatar
    • A skeleton loader appearing next to the fallback avatar

    The issue appears when navigating to Account because the ReportScreen useEffect at line 700-709 fires when the user returns to focus the app, attempting to rejoin the thread they just left - but it does so without the personal details, corrupting the avatar display state.

  6. MelvinBot commented on Mar 24, 2026

    @MelvinBot
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After leaving a system message thread (e.g., an "amount edited" system message) via the 3-dot context menu, the user's account avatar changes to a fallback avatar and a skeleton loader appears. This was introduced by PR #77636.

    What is the root cause of that problem?

    PR #77636 refactored openReport in src/libs/actions/Report/index.ts to accept personalDetails as an explicit parameter instead of reading the module-level allPersonalDetails variable directly. Most callers were updated to pass personalDetails, but toggleSubscribeToChildReport was not.

    When the user clicks "Leave thread" on a system message that has no existing child thread (childReportID is undefined), toggleSubscribeToChildReport enters its else branch (line ~3077) which creates a new optimistic report and calls openReport with newReportObject but without personalDetails:

    openReport({
        reportID: newChat.reportID,
        introSelected,
        participants,           // ✅ updated
        newReportObject: newChat,
        parentReportActionID: ...,
        betas,
        // ❌ personalDetails is NOT passed
    });
    

    Inside openReport, since personalDetails is undefined, the check at line ~1617:

    const isOptimisticAccount = !personalDetails?.[accountID];
    

    evaluates to true for every participant (including the current user). This causes optimistic personal details with isOptimisticPersonalDetail: true to be merged into PERSONAL_DETAILS_LIST for all participants.

    Then, when the API response arrives, the HandleUnusedOptimisticID middleware (src/libs/Middleware/HandleUnusedOptimisticID.ts) calls prepareOnyxDataForCleanUpOptimisticParticipants, which finds all participants now flagged with isOptimisticPersonalDetail: true and nulls out their personal details entries. This deletes the current user's personal details from Onyx, causing the fallback avatar and skeleton loader.

    What changes do you think we should make in order to solve the problem?

    In toggleSubscribeToChildReport (src/libs/actions/Report/index.ts, line ~3092), pass personalDetails: allPersonalDetails in the openReport call within the else branch:

    openReport({
        reportID: newChat.reportID,
        introSelected,
        participants,
        personalDetails: allPersonalDetails,  // ← add this
        newReportObject: newChat,
        parentReportActionID: parentReportAction.reportActionID,
        betas,
    });
    

    This ensures existing participants are correctly recognized as non-optimistic accounts, preventing the erroneous cleanup of their personal details.

    What alternative solutions did you explore? (Optional)

    An alternative would be to make openReport fall back to allPersonalDetails when personalDetails is not provided (i.e., const detailsToUse = personalDetails ?? allPersonalDetails), similar to what navigateToAndOpenReportWithAccountIDs does. However, the purpose of PR #77636 was to move away from using the module-level variable, so passing it explicitly is more consistent with the intended refactoring direction.


    Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot <your feedback> to refine this analysis, or explain why you are rejecting Melvin's proposal.

  7. changed the title [-]Expense - After leaving system message thread, account avatar changes to fallback avatar[/-] [+][RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar[/+] on Mar 24, 2026
  8. 6 remaining items

  9. added
    Awaiting PaymentAuto-added when associated PR is deployed to production
    and removed on Mar 25, 2026
  10. changed the title [-][RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar[/-] [+][Due for payment 2026-04-01] [RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar[/+] on Mar 25, 2026
  11. melvin-bot commented on Mar 25, 2026

    @melvin-bot

    Reviewing label has been removed, please complete the "BugZero Checklist".

  12. melvin-bot commented on Mar 25, 2026

    @melvin-bot

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.43-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-04-01. 🎊

  13. melvin-bot commented on Mar 25, 2026

    @melvin-bot

    @AndrewGable The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero 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]

  14. melvin-bot commented on Mar 25, 2026

    @melvin-bot

    Triggered auto assignment to @mallenexpensify (Awaiting Payment)

  15. changed the title [-][Due for payment 2026-04-01] [RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar[/-] [+][Due for payment 2026-04-02] [Due for payment 2026-04-01] [RCA #77636] Expense - After leaving system message thread, account avatar changes to fallback avatar[/+] on Mar 26, 2026
  16. melvin-bot commented on Mar 26, 2026

    @melvin-bot

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.48-2 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-04-02. 🎊

  17. melvin-bot commented on Mar 26, 2026

    @melvin-bot

    @AndrewGable @mallenexpensify The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero 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]

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

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.EngineeringWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions