[GH-ISSUE #7391] [Maintenance] Add scoped ErrorBoundaries to isolate feature-level crashes #100484

Open
opened 2026-05-29 20:13:12 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @MatissJanis on GitHub (Apr 5, 2026).
Original GitHub issue: https://github.com/actualbudget/actual/issues/7391

Summary

When a component throws a rendering error, the entire app crashes to the "Fatal Error" screen. This happens because we only have two top-level ErrorBoundary wrappers (in App.tsx) and one feature-scoped boundary (in GetCardData.tsx for report charts).

Adding scoped ErrorBoundary components around major features would contain failures to the affected area instead of taking down the whole app.

Problem

A single rendering error in any feature — budget, accounts, transactions, reports, schedules, rules — crashes the entire application. Users lose all context and must restart.

This is a recurring pattern. Across open and closed issues, there are 70+ reports of fatal crashes caused by component-level errors that could have been contained:

Currently open:

  • #7273 — Fatal Error after reports .json file import
  • #7285 — Fatal Error viewing ledgers with recurring transactions ending in the past
  • #7098 — Custom Report bars crash
  • #7108 — Calendar widget crashes on mobile
  • #6073 — Hide reconciled transactions crashes app
  • #7358 — Dollar sign in Schedule Name crashes app
  • #6317 — Backslash in rule notes causes crash
  • #5351 — API Unhandled Rejection

Recurring crash patterns from closed issues:

The fix for #4703 (adding an ErrorBoundary around modals) shows this approach works. We should apply it systematically.

Proposed approach

Wrap major feature areas with ErrorBoundary from react-error-boundary (already a dependency at v6.0.3). Each boundary should:

  1. Catch and contain the error to that feature area
  2. Show a contextual fallback (e.g., "This report couldn't be loaded" instead of a full-app fatal screen)
  3. Offer a retry via resetErrorBoundary where it makes sense

A shared FeatureErrorFallback component now lives at packages/desktop-client/src/components/FeatureErrorFallback.tsx and is used by all completed boundaries — please reuse it for consistency.

Suggested areas to add boundaries

Desktop / shared

Status Area Entry point(s) Related crashes
Budget table BudgetTable / BudgetPageHeader (wrapped in DynamicBudgetTable.tsx) #5969, #6073
Account ledger Account component (accounts/Account.tsx) #7285, #3263, #595
Transaction list TransactionList (transactions/TransactionList.tsx) #5304, #1021
🔴 Reports (individual) Each full-page report view — NetWorth.tsx, CashFlow.tsx, Spending.tsx, CustomReport.tsx, Calendar.tsx, BalanceForecast.tsx, Sankey.tsx, Summary.tsx, AgeOfMoney.tsx, Crossover.tsx, Formula.tsx, BudgetAnalysis.tsx #7273, #7098, #5814, #5764, #6221
Schedules Schedules page (schedules/index.tsx) #7358, #3989, #3954
Rules Rules page (ManageRulesPage.tsx, plus route-level wrapping in FinancesApp.tsx) #6317, #6885, #4013, #2180
Sidebar Sidebar component (sidebar/Sidebar.tsx) #5467
Dashboard widgets Individual widget cards (per-card boundary in reports/Overview.tsx) #7108, #6313
Individual modals Each modal content (boundary in common/Modal.tsx) #4703 pattern

Mobile

None of the mobile entry points currently have feature-scoped boundaries — grep -r "ErrorBoundary" packages/desktop-client/src/components/mobile/ returns zero hits. Several of the linked crashes (#7108, #6650, #6467, #5692, #4204, #3263) are mobile-specific, so each of these pages should mirror its desktop counterpart.

Status Area Entry point(s)
🔴 Mobile budget mobile/budget/BudgetPage.tsx (wrapping BudgetTable)
🔴 Mobile category transactions mobile/budget/CategoryPage.tsx / CategoryTransactions.tsx
🔴 Mobile accounts list mobile/accounts/AccountsPage.tsx
🔴 Mobile account ledger mobile/accounts/AccountPage.tsx (and the *AccountTransactions.tsx variants)
🔴 Mobile transaction list mobile/transactions/TransactionList.tsx / TransactionListWithBalances.tsx
🔴 Mobile transaction edit mobile/transactions/TransactionEdit.tsx
🔴 Mobile schedules mobile/schedules/MobileSchedulesPage.tsx (and MobileScheduleEditPage.tsx)
🔴 Mobile rules mobile/rules/MobileRulesPage.tsx (and MobileRuleEditPage.tsx)
🔴 Mobile payees mobile/payees/MobilePayeesPage.tsx (and MobilePayeeEditPage.tsx)
🔴 Mobile bank sync mobile/banksync/MobileBankSyncPage.tsx (and MobileBankSyncAccountEditPage.tsx)

Implementation notes

  • react-error-boundary v6 is already a dependency — no new packages needed
  • FatalError.tsx has good patterns for error display that can be adapted
  • The shared FeatureErrorFallback component keeps UX consistent across boundaries
  • Each boundary can use onError to log to the existing notification system

This is a good first contribution

Each remaining boundary is a small, self-contained change — pick a report view or a mobile page from the tables above. The pattern is straightforward:

import { ErrorBoundary } from 'react-error-boundary';
import { FeatureErrorFallback } from '#components/FeatureErrorFallback';

<ErrorBoundary FallbackComponent={FeatureErrorFallback}>
  <YourFeatureComponent />
</ErrorBoundary>
Originally created by @MatissJanis on GitHub (Apr 5, 2026). Original GitHub issue: https://github.com/actualbudget/actual/issues/7391 ## Summary When a component throws a rendering error, the entire app crashes to the "Fatal Error" screen. This happens because we only have two top-level `ErrorBoundary` wrappers (in `App.tsx`) and one feature-scoped boundary (in `GetCardData.tsx` for report charts). Adding scoped `ErrorBoundary` components around major features would contain failures to the affected area instead of taking down the whole app. ## Problem A single rendering error in any feature — budget, accounts, transactions, reports, schedules, rules — crashes the entire application. Users lose all context and must restart. This is a recurring pattern. Across open and closed issues, there are **70+ reports** of fatal crashes caused by component-level errors that could have been contained: **Currently open:** - #7273 — Fatal Error after reports .json file import - #7285 — Fatal Error viewing ledgers with recurring transactions ending in the past - #7098 — Custom Report bars crash - #7108 — Calendar widget crashes on mobile - #6073 — Hide reconciled transactions crashes app - #7358 — Dollar sign in Schedule Name crashes app - #6317 — Backslash in rule notes causes crash - #5351 — API Unhandled Rejection **Recurring crash patterns from closed issues:** - **Filter condition changes** (is ↔ one-of switching) — #6446, #6479, #6325, #6452, #6590, #5476, #5347 - **Reports/charts rendering** — #6221, #5814, #5729, #5764, #6406, #1792, #4307 - **Rules and schedules** — #6885, #6422, #6160, #5258, #4013, #3989, #3954, #2180 - **Date field handling** — #5304, #5094, #5969 - **Mobile/browser-specific** — #6650, #6467, #5692, #4204, #3263 - **Modals** — #4703 (fixed by adding an ErrorBoundary — proving the pattern works) The fix for #4703 (adding an ErrorBoundary around modals) shows this approach works. We should apply it systematically. ## Proposed approach Wrap major feature areas with `ErrorBoundary` from `react-error-boundary` (already a dependency at v6.0.3). Each boundary should: 1. **Catch and contain** the error to that feature area 2. **Show a contextual fallback** (e.g., "This report couldn't be loaded" instead of a full-app fatal screen) 3. **Offer a retry** via `resetErrorBoundary` where it makes sense A shared `FeatureErrorFallback` component now lives at `packages/desktop-client/src/components/FeatureErrorFallback.tsx` and is used by all completed boundaries — please reuse it for consistency. ### Suggested areas to add boundaries #### Desktop / shared | Status | Area | Entry point(s) | Related crashes | |--------|------|----------------|-----------------| | ✅ | Budget table | `BudgetTable` / `BudgetPageHeader` (wrapped in `DynamicBudgetTable.tsx`) | #5969, #6073 | | ✅ | Account ledger | `Account` component (`accounts/Account.tsx`) | #7285, #3263, #595 | | ✅ | Transaction list | `TransactionList` (`transactions/TransactionList.tsx`) | #5304, #1021 | | 🔴 | Reports (individual) | Each full-page report view — `NetWorth.tsx`, `CashFlow.tsx`, `Spending.tsx`, `CustomReport.tsx`, `Calendar.tsx`, `BalanceForecast.tsx`, `Sankey.tsx`, `Summary.tsx`, `AgeOfMoney.tsx`, `Crossover.tsx`, `Formula.tsx`, `BudgetAnalysis.tsx` | #7273, #7098, #5814, #5764, #6221 | | ✅ | Schedules | `Schedules` page (`schedules/index.tsx`) | #7358, #3989, #3954 | | ✅ | Rules | `Rules` page (`ManageRulesPage.tsx`, plus route-level wrapping in `FinancesApp.tsx`) | #6317, #6885, #4013, #2180 | | ✅ | Sidebar | `Sidebar` component (`sidebar/Sidebar.tsx`) | #5467 | | ✅ | Dashboard widgets | Individual widget cards (per-card boundary in `reports/Overview.tsx`) | #7108, #6313 | | ✅ | Individual modals | Each modal content (boundary in `common/Modal.tsx`) | #4703 pattern | #### Mobile None of the mobile entry points currently have feature-scoped boundaries — `grep -r "ErrorBoundary" packages/desktop-client/src/components/mobile/` returns zero hits. Several of the linked crashes (#7108, #6650, #6467, #5692, #4204, #3263) are mobile-specific, so each of these pages should mirror its desktop counterpart. | Status | Area | Entry point(s) | |--------|------|----------------| | 🔴 | Mobile budget | `mobile/budget/BudgetPage.tsx` (wrapping `BudgetTable`) | | 🔴 | Mobile category transactions | `mobile/budget/CategoryPage.tsx` / `CategoryTransactions.tsx` | | 🔴 | Mobile accounts list | `mobile/accounts/AccountsPage.tsx` | | 🔴 | Mobile account ledger | `mobile/accounts/AccountPage.tsx` (and the `*AccountTransactions.tsx` variants) | | 🔴 | Mobile transaction list | `mobile/transactions/TransactionList.tsx` / `TransactionListWithBalances.tsx` | | 🔴 | Mobile transaction edit | `mobile/transactions/TransactionEdit.tsx` | | 🔴 | Mobile schedules | `mobile/schedules/MobileSchedulesPage.tsx` (and `MobileScheduleEditPage.tsx`) | | 🔴 | Mobile rules | `mobile/rules/MobileRulesPage.tsx` (and `MobileRuleEditPage.tsx`) | | 🔴 | Mobile payees | `mobile/payees/MobilePayeesPage.tsx` (and `MobilePayeeEditPage.tsx`) | | 🔴 | Mobile bank sync | `mobile/banksync/MobileBankSyncPage.tsx` (and `MobileBankSyncAccountEditPage.tsx`) | ### Implementation notes - `react-error-boundary` v6 is already a dependency — no new packages needed - `FatalError.tsx` has good patterns for error display that can be adapted - The shared `FeatureErrorFallback` component keeps UX consistent across boundaries - Each boundary can use `onError` to log to the existing notification system ## This is a good first contribution Each remaining boundary is a small, self-contained change — pick a report view or a mobile page from the tables above. The pattern is straightforward: ```tsx import { ErrorBoundary } from 'react-error-boundary'; import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; <ErrorBoundary FallbackComponent={FeatureErrorFallback}> <YourFeatureComponent /> </ErrorBoundary> ```
GiteaMirror added the help wantedtech debtmaintenancegood first issue labels 2026-05-29 20:13:20 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Apr 5, 2026):

Thanks for sharing your idea!

This repository uses a voting-based system for feature requests. While enhancement issues are automatically closed, we still welcome feature requests! The voting system helps us gauge community interest in potential features. We also encourage community contributions for any feature requests marked as needing votes (just post a comment first so we can help guide you toward a successful contribution).

The enhancement backlog can be found here: https://github.com/actualbudget/actual/issues?q=label%3A%22needs+votes%22+sort%3Areactions-%2B1-desc+

Don't forget to upvote the top comment with 👍!

<!-- gh-comment-id:4189503724 --> @github-actions[bot] commented on GitHub (Apr 5, 2026): :sparkles: Thanks for sharing your idea! :sparkles: This repository uses a voting-based system for feature requests. While enhancement issues are automatically closed, we still welcome feature requests! The voting system helps us gauge community interest in potential features. We also encourage community contributions for any feature requests marked as needing votes (just post a comment first so we can help guide you toward a successful contribution). The enhancement backlog can be found here: https://github.com/actualbudget/actual/issues?q=label%3A%22needs+votes%22+sort%3Areactions-%2B1-desc+ Don't forget to upvote the top comment with 👍! <!-- feature-auto-close-comment -->
Author
Owner

@MatissJanis commented on GitHub (May 15, 2026):

Looks like most desktop error boundaries have been added! 🎉

Updated the list in issue description. We should also expand the ErrorBoundaries to mobile. Anyone: feel free to take this on!

<!-- gh-comment-id:4461763860 --> @MatissJanis commented on GitHub (May 15, 2026): Looks like most desktop error boundaries have been added! 🎉 Updated the list in issue description. We should also expand the ErrorBoundaries to mobile. Anyone: feel free to take this on!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#100484