Drop redundant bootstrap error boundary

React Router routes render and loader errors to the route-level
boundaries, so the App-level boundary above the router could only catch
provider render failures — which today are trivial — while true bootstrap
failures throw at module load before it mounts. Neither console nor trust
wraps App this way.

Rely on the root route boundary instead and remove the BootstrapError
fallback it used.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-07-15 09:43:46 +02:00
parent 63c7d88bd2
commit acf710d80c
4 changed files with 5 additions and 54 deletions

View File

@@ -18,19 +18,15 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import { ErrorBoundary } from "@probo/ui/src/v2/ErrorBoundary/ErrorBoundary";
import { RouterProvider } from "react-router";
import { BootstrapError } from "#/components/errors/BootstrapError";
import { RelayProvider } from "#/lib/relay/RelayProvider";
import { router } from "#/routes";
export function App() {
return (
<ErrorBoundary fallback={<BootstrapError />}>
<RelayProvider>
<RouterProvider router={router} />
</RelayProvider>
</ErrorBoundary>
<RelayProvider>
<RouterProvider router={router} />
</RelayProvider>
);
}

View File

@@ -1,45 +0,0 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { Anchor } from "@probo/ui/src/v2/Button/Anchor";
import { Button } from "@probo/ui/src/v2/Button/Button";
import { ErrorState } from "@probo/ui/src/v2/ErrorState/ErrorState";
import { useTranslation } from "react-i18next";
import { getPathPrefix } from "#/lib/http/pathPrefix";
// Outermost fallback for failures that happen before (or in) the router itself.
// It cannot use the router (no context yet), so navigation is a plain anchor and
// recovery is a hard reload.
export function BootstrapError() {
const { t } = useTranslation();
return (
<ErrorState
fullPage
title={t("errors.generic.title")}
description={t("errors.generic.description")}
actions={(
<>
<Anchor href={getPathPrefix() || "/"} variant="solid" color="neutral" highContrast size={2}>
{t("errors.actions.backToTrustCenter")}
</Anchor>
<Button variant="soft" color="neutral" size={2} onClick={() => window.location.reload()}>
{t("errors.actions.tryAgain")}
</Button>
</>
)}
/>
);
}

View File

@@ -61,7 +61,7 @@ interface GlobalErrorProps {
}
// Page-level error fallback: renders the v2 ErrorState with portal copy and
// actions. Used by the bootstrap boundary and the route boundaries.
// actions. Used by the route boundaries (root + page).
export function GlobalError({ error, onRetry, fullPage = false }: GlobalErrorProps) {
const { t } = useTranslation();
const { code, titleKey, descriptionKey } = resolveContent(error);

View File

@@ -211,7 +211,7 @@ The portal ships three fallback tiers, all backed by the same `ErrorBoundary`:
| Tier | Placement | Fallback |
|------|-----------|----------|
| Global (bootstrap) | around `RouterProvider` in `App.tsx`, and the root route | `ErrorState` full page (standalone) |
| Global | root route (`RootErrorBoundary`) | `ErrorState` full page (standalone) |
| Page | pathless child route inside the layout | `ErrorState` inside the shell (TopBar/footer survive) |
| Section / row | around a fragment-reading subtree | `InlineError` (vertical for sections, horizontal for rows) with a retry |