[$250] Expense - Report loads infinitely after deleting split and opening the empty report
If you havenโt already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!
Version Number: 9.2.62-0 Reproducible in staging?: Y Reproducible in production?: Y If this was caught during regression testing, add the test name, ID and link from TestRail: https://test-management.browserstack.com/projects/2219752/test-runs/TR-2116/folder/13176670/41237133/1030266308 Email or phone of affected tester (no customers): [email protected] Issue reported by: Applause - Internal Team
Action Performed:
- Go to staging.new.expensify.com
- Go to workspace chat
- Create an expense
- Open the expense report
- Click More > Split
- Click Save
- Open any split
- Click Report field > Create report
- Go back to workspace chat
- Right click on the report with one split > Delete
- Delete the report
- Click on the empty report
Expected Result:
The empty report will open
Actual Result:
Report loads infinitely after deleting split and opening the empty report
Workaround:
Unknown
Platforms:
Select the officially supported platforms where the issue was reproduced:
- [x] Android: App
- [x] Android: mWeb Chrome
- [x] iOS: App
- [x] iOS: mWeb Safari
- [x] iOS: mWeb Chrome
- [x] Windows: Chrome
- [x] MacOS: Chrome / Safari
- [x] MacOS: Desktop
Platforms Tested:
On which of our officially supported platforms was this issue tested:- [ ] Android: App
- [ ] Android: mWeb Chrome
- [ ] iOS: App
- [ ] iOS: mWeb Safari
- [ ] iOS: mWeb Chrome
- [ ] Windows: Chrome
- [ ] MacOS: Chrome / Safari
- [ ] MacOS: Desktop
Screenshots/Videos
Add any screenshot/video evidence
https://github.com/user-attachments/assets/abbfb250-68fa-4ee9-a533-50f661f374be
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~021992713496560374472
- Upwork Job ID: 1992713496560374472
- Last Price Increase: 2025-12-21
Issue Owner
Current Issue Owner: @hoangzinh
Triggered auto assignment to @VictoriaExpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.
๐จ Edited by proposal-police: This proposal was edited at 2025-11-25 13:11:11 UTC.
Proposal
Please re-state the problem that we are trying to solve in this issue.
Report loads infinitely after deleting split and opening the empty report
What is the root cause of that problem?
When user deletes a report with split expenses, all transactions are removed from the report. And the shouldWaitForTransactions function had this logic:
- Since transactions.length === 0 AND report.total !== 0, the condition evaluated to true
- This caused shouldWaitForTransactions to return true
https://github.com/Expensify/App/blob/4468cb2a719511355dbabcf750dfe9e051e35829/src/libs/MoneyRequestReportUtils.ts#L116-L126
Thus, the skeleton loading screen shows infinitely here
https://github.com/Expensify/App/blob/74d28a7eccdc58ead12db528ae2cbdde2a5c7a9c/src/pages/home/ReportScreen.tsx#L960
What changes do you think we should make in order to solve the problem?
We can update shouldWaitForTransactions function to use a more reliable condition for determining if data is still loading
function shouldWaitForTransactions(report: OnyxEntry<Report>, transactions: Transaction[] | undefined, reportMetadata: OnyxEntry<ReportMetadata>) {
const isTransactionDataReady = transactions !== undefined;
const isTransactionThreadView = isReportTransactionThread(report);
// Don't wait for transactions if the report is being deleted
const isReportBeingDeleted = report?.pendingFields?.preview === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
// If we have no transactions and the report has been loaded at least once, don't wait
// This handles the case where a report was deleted and still has a total value but no transactions
const hasLoadedReportActions = reportMetadata?.hasOnceLoadedReportActions;
const isStillLoadingData = transactions?.length === 0 && !hasLoadedReportActions && !!reportMetadata?.isLoadingInitialReportActions;
const result = (
(isMoneyRequestReport(report) || isInvoiceReport(report)) &&
(!isTransactionDataReady || isStillLoadingData) &&
!isTransactionThreadView &&
!isReportBeingDeleted &&
report?.pendingFields?.createReport !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD
);
return result;
}
https://github.com/Expensify/App/blob/4468cb2a719511355dbabcf750dfe9e051e35829/src/libs/MoneyRequestReportUtils.ts#L116-L126
What alternative solutions did you explore? (Optional)
Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
Yeah we should fix this
Job added to Upwork: https://www.upwork.com/jobs/~021992713496560374472
Triggered auto assignment to Contributor-plus team member for initial proposal review - @hoangzinh (External)
@lorretheboy Thanks for posting proposal. Can you help me understand why "the report metadata is NOT cleaned up" causes report loads infinite? TY
I updated the proposal to follow new approach, the previous solution works for the first time but will break again if we clear the cache. Could you please re-review it? @hoangzinh
Since transactions.length === 0 AND report.total !== 0, the condition evaluated to true
@lorretheboy, do you think we can optimistically update report.total to equal 0 in this case to fix this issue?
๐ฃ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? ๐ธ
@hoangzinh Whoops! This issue is 2 days overdue. Let's get this updated quick!
Awaiting proposals.
cc @lorretheboy
No new approach from my side, I only figure out the solution by update the shouldWaitForTransactions @hoangzinh
@lorretheboy Uhm, do you think we should also delete the money report instead of leaving it as an empty report in this case?
@hoangzinh I'm not sure tbh, maybe we can ask internal team about this?
@hoangzinh @VictoriaExpensify this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!
๐ฃ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? ๐ธ
I think we should delete report in this case, similar with normal expense case. @VictoriaExpensify do you agree with this expectation?
https://github.com/user-attachments/assets/f6dd86e1-7984-4d2a-9573-9c7864ed7458
@hoangzinh Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!
๐ฃ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? ๐ธ
Asked @VictoriaExpensify on Slack about her thoughts on https://github.com/Expensify/App/issues/75783#issuecomment-3627045881
Asked @VictoriaExpensify on Slack about her thoughts on https://github.com/Expensify/App/issues/75783#issuecomment-3627045881
@hoangzinh If @VictoriaExpensify agreed on this comment then I want to take this issue as an external contributor by submitting the proposal.
Yes, feel free to submit your proposal @Uzaifm127.
๐จ Edited by proposal-police: This proposal was edited at 2025-12-17 10:12:19 UTC.
Proposal
Please re-state the problem that we are trying to solve in this issue.
The report loads infinitely after deleting a split and opening the empty report.
What is the root cause of that problem?
In the removed report, report.total is still retained and not cleared, causing isStillLoadingData to remain true, which makes the shouldWaitForTransactions function return true
https://github.com/Expensify/App/blob/c4d51cfac96f7181511cd4911e5acc93c4813ebd/src/libs/MoneyRequestReportUtils.ts#L122-L130
As a result, ReportScreen displays the loading skeleton indefinitely.
https://github.com/Expensify/App/blob/c4d51cfac96f7181511cd4911e5acc93c4813ebd/src/pages/home/ReportScreen.tsx#L353
https://github.com/Expensify/App/blob/c4d51cfac96f7181511cd4911e5acc93c4813ebd/src/pages/home/ReportScreen.tsx#L991
What changes do you think we should make in order to solve the problem?
In shouldWaitForTransactions, the report.total condition (added in PR https://github.com/Expensify/App/pull/71190) should be stricter.
Suggested update:
const isStillLoadingData = transactions?.length === 0 &&
((!!reportMetadata?.isLoadingInitialReportActions && !reportMetadata.hasOnceLoadedReportActions)
|| (report?.total !== 0 && report?.transactionCount !== 0));
Also, ensure transactionCount is added to the report:
transactionCount: reportOnyx.transactionCount,
Reference:
https://github.com/Expensify/App/blob/c4d51cfac96f7181511cd4911e5acc93c4813ebd/src/pages/home/ReportScreen.tsx#L285
What alternative solutions did you explore? (Optional)
Removing the report completely
First, we need to get the current transactions of the report using the useTransactionsAndViolationsForReport hook. Next, we compare these current transactions with the transactionIDs parameter passed to the deleteTransactions function:
https://github.com/Expensify/App/blob/466a83d596954a6b3ef5fa7cf1c07aab1429f681/src/hooks/useDeleteTransactions.ts#L52
If the removed transactionIDs fully match the current transactions of the report, it means the user is attempting to remove all transactions from that report. In this case, we will call the deleteAppReport API to fully remove the report and return early to avoid calling the updateSplitTransactions/deleteMoneyRequest API anymore
@hoangzinh Whoops! This issue is 2 days overdue. Let's get this updated quick!
@hoangzinh @VictoriaExpensify this issue is now 4 weeks old, please consider:
- Finding a contributor to fix the bug
- Closing the issue if BZ has been unable to add the issue to a VIP or Wave project
- If you have any questions, don't hesitate to start a discussion in #expensify-open-source
Thanks!
๐ฃ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? ๐ธ
@hoangzinh 6 days overdue. This is scarier than being forced to listen to Vogon poetry!
Reviewing today
@cretadn22 I'm interested in your alternative solution, is it possible to call deleteMoneyRequest after updateSplitTransactions when the split transaction is the last one on the report?
is it possible to call deleteMoneyRequest after updateSplitTransactions when the split transaction is the last one on the report?
@hoangzinh That approach is possible, but Iโm a bit concerned it may not be allowed per the documentation, since it involves calling two consecutive APIs for a single user action.
https://github.com/Expensify/App/blob/54c7eb47b7e774379769129367bc930dbdfb976f/contributingGuides/API.md?plain=1#L5-L6