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 - “Amount · Non-reimbursable” does not appear immediately after deleting expense #91058
Version Number: 9.3.77-0 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:#90411 Email or phone of affected tester (no customers):sdsdjoijdoisnjodis@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:
Go to staging.new.expensify.com
Go to workspace chat.
Create two non-reimbursable expenses.
Open expense report.
Open both expenses.
Delete one of the expenses.
Expected Result:
“Amount · Non-reimbursable” will appear on the remaining expense immediately.
Actual Result:
Reimbursable and Non-reimbursable row appear briefly, then it shows “Amount · Non-reimbursable”.
👋 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.
Classification: Frontend bug Causing PR: #90411 - "Hide redundant Reimbursable rows; show '. Non-reimbursable' on Amount" by @mukhrr (High confidence) Related Issues: #89548
Recommendation: REVERT
PR #90411 introduced the logic for hiding the breakdown rows when a single non-reimbursable expense is present. The bug is a UI flash caused by a race condition in the new logic during expense deletion — reverting this PR will restore the previous stable behavior.
Assigned: @mukhrr (PR author), @hoangzinh and @rlinoz (approving reviewers) Labels: DeployBlockerCash kept (frontend App PR is the cause). No label changes made.
isSingleTransactionReport checks transactions.length === 1 using data from useReportTransactions, which reads from the Onyx TRANSACTION collection. When the user deletes one of two non-reimbursable expenses, the Onyx state updates asynchronously: the transactions array (from the collection) drops to length 1 before the report-level nonReimbursableSpend field is updated. During this brief window, isSingleNonReimbursableExpense is false (because both values haven't settled yet — e.g., the remaining transaction may still have reimbursable as undefined transiently), causing shouldShowBreakdown to evaluate to true and both "Reimbursable" and "Non-reimbursable" rows to flash before the correct state is reached.
When a transaction is deleted, the optimistic update marks it with pendingAction: DELETE but does not remove it from Onyx — the actual removal only happens in successData after the API responds. Meanwhile, the report's total and nonReimbursableTotalare updated optimistically in the same batch.
This creates a brief intermediate state where useReportTransactions still returns 2 transactions (it doesn't filter out pendingAction: DELETE), so isSingleTransactionReport returns false. That makes isSingleNonReimbursableExpensefalse, which in turn makes shouldShowBreakdowntrue — causing the Reimbursable/Non-reimbursable breakdown rows to flash before the transaction is fully removed and the view settles.
What changes do you think we should make in order to solve the problem?
In MoneyReportView.tsx, filter out transactions with pendingAction === DELETE before passing them to isSingleTransactionReport and using the count for isSingleNonReimbursableExpense. This keeps the transaction-count logic in sync with the already-optimistically-updated report totals, preventing the intermediate state from producing a visible flicker.
This is a local filter in the component rather than a change to useReportTransactions globally, which avoids unintended side effects elsewhere (e.g., pending-delete transactions still need to render with strikethrough styling in list views).
What alternative solutions did you explore? (Optional)
Filtering pendingAction: DELETE transactions globally in useReportTransactions was considered but rejected — other consumers of that hook rely on seeing pending-delete transactions to render them with appropriate visual indicators (strikethrough, opacity). A component-local filter is the minimal, safe change.
Supporting evidence
Data flow during the flicker:
User deletes one of two non-reimbursable expenses
Optimistic update: transaction gets pendingAction: DELETE (stays in Onyx); report totals are reduced
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.
Not repro, Chrome, Xiaomi Redmi Note 10 / Android 12v9.3.77-3. Note: on both platforms, after delete expense, user navigated to report details briefly (with 2 expenses) and only after - to the last expense details (Waiting for validation in iOS)
Activity
melvin-bot commentedon May 19, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #90411
melvin-bot commentedon May 19, 2026
💬 A slack conversation has been started in #expensify-open-source
github-actions commentedon May 19, 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:
OSBotify commentedon May 19, 2026
Investigation Summary
Classification: Frontend bug
Causing PR: #90411 - "Hide redundant Reimbursable rows; show '. Non-reimbursable' on Amount" by @mukhrr (High confidence)
Related Issues: #89548
Recommendation: REVERT
PR #90411 introduced the logic for hiding the breakdown rows when a single non-reimbursable expense is present. The bug is a UI flash caused by a race condition in the new logic during expense deletion — reverting this PR will restore the previous stable behavior.
Assigned: @mukhrr (PR author), @hoangzinh and @rlinoz (approving reviewers)
Labels:
DeployBlockerCashkept (frontend App PR is the cause). No label changes made.Detailed Analysis
Evidence
src/components/ReportActionItem/MoneyReportView.tsx— the exact component that renders the breakdown rows reported in the bug.Verification
src/components/ReportActionItem/MoneyReportView.tsxandsrc/components/ReportActionItem/MoneyRequestView.tsxRoot Cause
PR #90411 added
isSingleNonReimbursableExpenselogic inMoneyReportView.tsx:isSingleTransactionReportcheckstransactions.length === 1using data fromuseReportTransactions, which reads from the OnyxTRANSACTIONcollection. When the user deletes one of two non-reimbursable expenses, the Onyx state updates asynchronously: thetransactionsarray (from the collection) drops to length 1 before the report-levelnonReimbursableSpendfield is updated. During this brief window,isSingleNonReimbursableExpenseisfalse(because both values haven't settled yet — e.g., the remaining transaction may still havereimbursableasundefinedtransiently), causingshouldShowBreakdownto evaluate totrueand both "Reimbursable" and "Non-reimbursable" rows to flash before the correct state is reached.MelvinBot commentedon May 19, 2026
Proposal
What is the root cause of that problem?
When a transaction is deleted, the optimistic update marks it with
pendingAction: DELETEbut does not remove it from Onyx — the actual removal only happens insuccessDataafter the API responds. Meanwhile, the report'stotalandnonReimbursableTotalare updated optimistically in the same batch.This creates a brief intermediate state where
useReportTransactionsstill returns 2 transactions (it doesn't filter outpendingAction: DELETE), soisSingleTransactionReportreturnsfalse. That makesisSingleNonReimbursableExpensefalse, which in turn makesshouldShowBreakdowntrue— causing the Reimbursable/Non-reimbursable breakdown rows to flash before the transaction is fully removed and the view settles.What changes do you think we should make in order to solve the problem?
In
MoneyReportView.tsx, filter out transactions withpendingAction === DELETEbefore passing them toisSingleTransactionReportand using the count forisSingleNonReimbursableExpense. This keeps the transaction-count logic in sync with the already-optimistically-updated report totals, preventing the intermediate state from producing a visible flicker.This is a local filter in the component rather than a change to
useReportTransactionsglobally, which avoids unintended side effects elsewhere (e.g., pending-delete transactions still need to render with strikethrough styling in list views).What alternative solutions did you explore? (Optional)
Filtering
pendingAction: DELETEtransactions globally inuseReportTransactionswas considered but rejected — other consumers of that hook rely on seeing pending-delete transactions to render them with appropriate visual indicators (strikethrough, opacity). A component-local filter is the minimal, safe change.Supporting evidence
Data flow during the flicker:
pendingAction: DELETE(stays in Onyx); report totals are reduceduseReportTransactionsreturns 2 transactions →isSingleTransactionReport→false→shouldShowBreakdown→true→ breakdown rows appearnullin Onyx →useReportTransactionsreturns 1 →isSingleNonReimbursableExpense→true→ breakdown rows disappear → "Amount · Non-reimbursable" shownKey code locations:
DeleteMoneyRequest.ts:676-681DeleteMoneyRequest.ts:826-830useReportTransactions(no DELETE filter):useReportTransactions.ts:18isSingleNonReimbursableExpense/shouldShowBreakdown:MoneyReportView.tsx:109-110Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR,@MelvinBot <your feedback>to refine this analysis, or explain why you are rejecting Melvin's proposal.hoangzinh commentedon May 19, 2026
We're trying to fix this DB here #91073
roryabraham commentedon May 19, 2026
requested retest: https://expensify.slack.com/archives/C09V78U42D8/p1779221912405999
m-natarajan commentedon May 19, 2026
Not repro, Chrome, Xiaomi Redmi Note 10 / Android 12v9.3.77-3. Note: on both platforms, after delete expense, user navigated to report details briefly (with 2 expenses) and only after - to the last expense details (Waiting for validation in iOS)
Screenrecorder-2026-05-19-23-29-43-395.mp4
bandicam.2026-05-19.23-23-38-898.mp4
hoangzinh commentedon May 20, 2026
We can close this issue. No payment required