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-13] [$175] New message indicator does not pop up on 1st message after going back online #102094
Version Number: 9.4.92-5 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught during regression testing, add the test name, ID and link from BrowserStack:#100033 Email or phone of affected tester (no customers):emady.syed123+nonadmin1@gmail.com Issue reported by: Applause Internal Team Bug source: Pull Request QA execution Device used: All App Component: Chat Report View
Action Performed:
Open App
Go to any expense with many comments
Scroll to top
Receive a message from other user
Tap on new message indicator
Go to troubleshoot and go offline
Go back to same expense from step 2 and add a comment
Go online
Go back to same expense and scroll to top
Receive One message and wait few moments
Receive another message
Expected Result:
New message indicator should pop up on 1st message after going back online
Actual Result:
New message indicator does not pop up on 1st message after going back online
⚠️ Medium confidence, from static analysis only — I could not drive NewDot in a browser on this run, so nothing below is runtime-verified.
What is the root cause of that problem?
In the expense (money request) report view, every new action that arrives over Pusher force-hides the floating new-message pill, including messages from other people.
Meanwhile the indicator is turned on by a separate path: when unreadMarkerReportActionIndex flips from -1, an effect re-runs the viewability check and shows the pill (useReportUnreadMessageScrollTracking.ts:179-185). Those two run in the same beat when a message lands, and the Pusher hide is deferred through TransitionTracker.runAfterTransitions, so it tends to land last and win — no indicator for that message.
The chat list does not have this problem: its equivalent handler returns early for other people's actions at useReportActionsNewActionLiveTail.ts:103, before it ever touches the counter.
This also explains why message 2 works. The list is oldest-first, so appending a message does not change the index of the already-marked message. Nothing re-shows the pill until FlashList emits a fresh viewability callback, which the next message's layout change produces.
Note the report says this reproduces in production, so this is pre-existing and not caused by #100033 — that PR moved this code but kept the ordering.
What changes do you think we should make in order to solve the problem?
In useMoneyRequestReportScroll.ts, move setIsFloatingMessageCounterVisible(false) below the isFromCurrentUser / ADD_COMMENT guard, so the pill is only dismissed when the user's own comment is about to scroll the list to the bottom. That matches what the chat list already does.
Add a regression test covering: scrolled away from the bottom, receive one action from another user, assert the counter stays visible.
Supporting detail and a second, separate defect
Why the offline steps matter (steps 6-8). They are most likely just how the tester reached the state the bug needs: scrolled up, report freshly re-read, then a live message arriving. Sending offline leaves lastReadTime behind lastVisibleActionCreated, so reopening the report at step 9 marks it read and clears the marker — a clean slate before message 1 lands.
Second defect, worth fixing while in here (may not cause this bug).useUnreadMarker.ts:110-117 computes earliestReceivedOfflineMessageIndex over sortedReportActions, but shouldDisplayNewMarkerOnReportAction.ts:205-226 uses it as an index into visibleReportActions. For this view those two arrays are in opposite orders: reportActions is newest-first, while visibleReportActions is oldest-first (useMoneyRequestReportVisibleActions.ts:93). Whenever a message does arrive while the user is offline, the marker scan is bounded by, and anchors "earliest offline message" to, the wrong row. The index should be computed in the visibleReportActions domain.
What to check to confirm or kill the main hypothesis. Log unreadMarkerReportActionID, unreadMarkerReportActionIndex, and isFloatingMessageCounterVisible on each render while running steps 9-11. If the marker ID is set for message 1 but the counter is false, the Pusher hide is the cause. If the marker ID stays null for message 1, the cause is upstream in useUnreadMarker instead and this proposal is wrong.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/102094) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
Please re-state the problem that we are trying to solve in this issue.
In an expense report (MoneyRequestReportView), when scrolled up and receiving a new message from another user after going back online, the floating new message indicator pill does not pop up on the first incoming message.
What is the root cause of that problem?
In src/components/MoneyRequestReportView/useMoneyRequestReportScroll.ts:224-232:
constonNewActionEvent=useEffectEvent((isFromCurrentUser: boolean,reportAction?: OnyxTypes.ReportAction)=>{TransitionTracker.runAfterTransitions({callback: ()=>{setIsFloatingMessageCounterVisible(false);// If a new comment is added from the current user, scroll to the bottom, otherwise leave the user position unchangedif(!isFromCurrentUser||reportAction?.actionName!==CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT){return;}
setIsFloatingMessageCounterVisible(false) is called unconditionally at line 227 — before the check determining whether the action is from the current user or another user.
When a message from another user arrives via Pusher:
useReportUnreadMessageScrollTracking.ts detects the new unread message and attempts to display the floating new message indicator pill.
Simultaneously, onNewActionEvent runs its deferred transition callback and calls setIsFloatingMessageCounterVisible(false).
Because the transition callback runs asynchronously after rendering, setIsFloatingMessageCounterVisible(false) overwrites the visible state and suppresses the floating pill for the incoming message.
In contrast, the chat report equivalent (useReportActionsNewActionLiveTail.ts:101) guards against actions not from the current user (if (!isFromCurrentUser) return;) before performing any scroll or pill state changes.
What changes do you think we should make in order to solve the problem?
In src/components/MoneyRequestReportView/useMoneyRequestReportScroll.ts:
Move setIsFloatingMessageCounterVisible(false) inside the current-user comment guard so that the counter is only dismissed when the current user's own comment is scrolling the view to the bottom:
constonNewActionEvent=useEffectEvent((isFromCurrentUser: boolean,reportAction?: OnyxTypes.ReportAction)=>{TransitionTracker.runAfterTransitions({callback: ()=>{// If a new comment is added from the current user, scroll to the bottom, otherwise leave the user position unchangedif(!isFromCurrentUser||reportAction?.actionName!==CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT){return;}setIsFloatingMessageCounterVisible(false);// Delay so the just-sent item has landed in the data before we jumpconstindex=visibleReportActions.findIndex((item)=>item.reportActionID===reportAction?.reportActionID);// ...
What alternative solutions did you explore? (Optional)
Gating setIsFloatingMessageCounterVisible(false) on viewability callbacks was considered, but FlashList viewability events already handle showing and hiding the floating indicator based on scroll position (useReportUnreadMessageScrollTracking.ts). onNewActionEvent should only ever dismiss the floating counter when the user submits their own comment and triggers an programmatic auto-scroll to the bottom.
changed the title [-][$175] New message indicator does not pop up on 1st message after going back online[/-][+][Due for payment 2026-10-13] [$175] New message indicator does not pop up on 1st message after going back online[/+]on Oct 6, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.3-4 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-13. 🎊
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]
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: N/A
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Activity
applause-bot commentedon Sep 23, 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/5a6a30fdd536af712859185fc7e6980ecdeff2af93bf3b5bf21bfde4cf227195
MelvinBot commentedon Sep 23, 2026
Proposal
What is the root cause of that problem?
In the expense (money request) report view, every new action that arrives over Pusher force-hides the floating new-message pill, including messages from other people.
src/components/MoneyRequestReportView/useMoneyRequestReportScroll.ts:224-232callssetIsFloatingMessageCounterVisible(false)on line 227 — before theisFromCurrentUserguard on line 229. So an incoming message from another user hides the indicator instead of leaving it alone.Meanwhile the indicator is turned on by a separate path: when
unreadMarkerReportActionIndexflips from-1, an effect re-runs the viewability check and shows the pill (useReportUnreadMessageScrollTracking.ts:179-185). Those two run in the same beat when a message lands, and the Pusher hide is deferred throughTransitionTracker.runAfterTransitions, so it tends to land last and win — no indicator for that message.The chat list does not have this problem: its equivalent handler returns early for other people's actions at
useReportActionsNewActionLiveTail.ts:103, before it ever touches the counter.This also explains why message 2 works. The list is oldest-first, so appending a message does not change the index of the already-marked message. Nothing re-shows the pill until FlashList emits a fresh viewability callback, which the next message's layout change produces.
Note the report says this reproduces in production, so this is pre-existing and not caused by #100033 — that PR moved this code but kept the ordering.
What changes do you think we should make in order to solve the problem?
In
useMoneyRequestReportScroll.ts, movesetIsFloatingMessageCounterVisible(false)below theisFromCurrentUser/ADD_COMMENTguard, so the pill is only dismissed when the user's own comment is about to scroll the list to the bottom. That matches what the chat list already does.Add a regression test covering: scrolled away from the bottom, receive one action from another user, assert the counter stays visible.
Supporting detail and a second, separate defect
Why the offline steps matter (steps 6-8). They are most likely just how the tester reached the state the bug needs: scrolled up, report freshly re-read, then a live message arriving. Sending offline leaves
lastReadTimebehindlastVisibleActionCreated, so reopening the report at step 9 marks it read and clears the marker — a clean slate before message 1 lands.Second defect, worth fixing while in here (may not cause this bug).
useUnreadMarker.ts:110-117computesearliestReceivedOfflineMessageIndexoversortedReportActions, butshouldDisplayNewMarkerOnReportAction.ts:205-226uses it as an index intovisibleReportActions. For this view those two arrays are in opposite orders:reportActionsis newest-first, whilevisibleReportActionsis oldest-first (useMoneyRequestReportVisibleActions.ts:93). Whenever a message does arrive while the user is offline, the marker scan is bounded by, and anchors "earliest offline message" to, the wrong row. The index should be computed in thevisibleReportActionsdomain.What to check to confirm or kill the main hypothesis. Log
unreadMarkerReportActionID,unreadMarkerReportActionIndex, andisFloatingMessageCounterVisibleon each render while running steps 9-11. If the marker ID is set for message 1 but the counter is false, the Pusher hide is the cause. If the marker ID staysnullfor message 1, the cause is upstream inuseUnreadMarkerinstead and this proposal is wrong.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/102094)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
view run
melvin-bot commentedon Sep 23, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @Pujan92 (
External)melvin-bot commentedon Sep 23, 2026
Unable to auto-create job on Upwork. The BZ team member should create it manually for this issue.
ashusatyarthi-wq commentedon Sep 26, 2026
Contributor details
Your Expensify account email: ashu.satyarthi.business@gmail.com Upwork Profile Link: https://www.upwork.com/freelancers/~01b8ab177d61dc225cProposal
Please re-state the problem that we are trying to solve in this issue.
In an expense report (MoneyRequestReportView), when scrolled up and receiving a new message from another user after going back online, the floating new message indicator pill does not pop up on the first incoming message.
What is the root cause of that problem?
In
src/components/MoneyRequestReportView/useMoneyRequestReportScroll.ts:224-232:setIsFloatingMessageCounterVisible(false)is called unconditionally at line 227 — before the check determining whether the action is from the current user or another user.When a message from another user arrives via Pusher:
useReportUnreadMessageScrollTracking.tsdetects the new unread message and attempts to display the floating new message indicator pill.onNewActionEventruns its deferred transition callback and callssetIsFloatingMessageCounterVisible(false).setIsFloatingMessageCounterVisible(false)overwrites the visible state and suppresses the floating pill for the incoming message.In contrast, the chat report equivalent (
useReportActionsNewActionLiveTail.ts:101) guards against actions not from the current user (if (!isFromCurrentUser) return;) before performing any scroll or pill state changes.What changes do you think we should make in order to solve the problem?
In
src/components/MoneyRequestReportView/useMoneyRequestReportScroll.ts:Move
setIsFloatingMessageCounterVisible(false)inside the current-user comment guard so that the counter is only dismissed when the current user's own comment is scrolling the view to the bottom:What alternative solutions did you explore? (Optional)
Gating
setIsFloatingMessageCounterVisible(false)on viewability callbacks was considered, but FlashList viewability events already handle showing and hiding the floating indicator based on scroll position (useReportUnreadMessageScrollTracking.ts).onNewActionEventshould only ever dismiss the floating counter when the user submits their own comment and triggers an programmatic auto-scroll to the bottom.melvin-bot commentedon Sep 28, 2026
@Pujan92 Eep! 4 days overdue now. Issues have feelings too...
melvin-bot commentedon Sep 30, 2026
@Pujan92 Still overdue 6 days?! Let's take care of this!
Pujan92 commentedon Oct 1, 2026
@MelvinBot proposal looks good, move
setIsFloatingMessageCounterVisible(false)below theisFromCurrentUserguard.🎀👀🎀 C+ reviewed
15 remaining items
[-][$175] New message indicator does not pop up on 1st message after going back online[/-][+][Due for payment 2026-10-13] [$175] New message indicator does not pop up on 1st message after going back online[/+]melvin-bot commentedon Oct 6, 2026
@Pujan92
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.3-4 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-13. 🎊
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 12, 2026
Triggered auto assignment to @mallenexpensify (
Awaiting Payment)melvin-bot commentedon Oct 12, 2026
Payment Summary
Resolving PRs:
Keep the new-message pill visible when another user's message arrives in an expense report #102794
Reviewer: @Pujan92 owed $175 via NewDot
BugZero Checklist (@mallenexpensify)
Pujan92 commentedon Oct 13, 2026
BugZero Checklist:
Bug classification
Source of bug:
Where bug was reported:
Who reported the bug:
[Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.
Link to comment: https://github.com/Expensify/App/pull/59664/changes#r4260152255
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: N/A
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue: https://github.com/Expensify/Expensify/issues/691943
Regression Test Proposal
Precondition: User A and User B are both members of an expense report that has enough comments to scroll.
Zapier Logs
Run ID: 00040eee-4941-a1b9-3c45-6dfe88182774mallenexpensify commentedon Oct 15, 2026
Payment Summary
Contributor+: @Pujan92 due $175 via NewDot
twisterdotcom commentedon Oct 15, 2026
$175 approved for @Pujan92 in Report ID: R00KriUZon70.
Zapier Logs
Run ID: 00040eee-5f73-adb1-afec-0647568d11a4SO: https://stackoverflowteams.com/c/expensify/questions/7582