Error pages
CAUTION
Experimental — not for production. Managed Data Mode SSR is available for evaluation and testing. Do not use it in production yet; the API and behaviour may change. In the meantime, continue using Webpack SSR.
sku turns route failures into document responses: the nearest React Router ErrorBoundary renders the UI, and the streamed response uses the matching HTTP status code.
Add an ErrorBoundary
When a loader fails, a route throws, or the URL does not match, readers should see your UI rather than a blank document. Attach an ErrorBoundary on a layout route so every child under it shares the same failure UI.
Without a route ErrorBoundary, React Router hydrates its default error UI over the SSR error HTML. That can briefly flash a stack trace before the default “Hey developer” page. Provide an ErrorBoundary on the root route to provide a nicer user experience.
sku uses React Router Error Boundaries:
import type { SkuRouteObject } from 'sku/runtime';
import { ErrorBoundary } from './ErrorBoundary';
import { RootLayout } from './RootLayout';
export const routes: SkuRouteObject[] = [
{
Component: RootLayout,
ErrorBoundary,
children: [{ index: true, lazy: () => import('./pages/home/home') }],
},
];import { isRouteErrorResponse, useRouteError } from 'react-router';
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<main>
<h1>
{error.status} {error.statusText}
</h1>
<p>{typeof error.data === 'string' ? error.data : null}</p>
</main>
);
}
return (
<main>
<h1>Something went wrong</h1>
</main>
);
}Use isRouteErrorResponse when you want different copy for HTTP-style failures (404, data() responses) versus unexpected throws.
What gets an ErrorBoundary
An ErrorBoundary on a route catches failures that happen while matching or rendering that route and its descendants. That includes:
- loader failures and thrown
data()responses 404for unmatched routes405when a mutation hits a route without anaction- sync
Componentthrows
Put the boundary high enough in the tree (often the root layout) so nested pages inherit it. You can also nest boundaries when a section needs its own failure UI.
Suspense failures during document SSR
Render-time data loading can reject a Suspense boundary while sku is still streaming the document. When that happens, sku aborts the first stream and re-renders with the error on the static handler context. The nearest ErrorBoundary then produces the HTML response (status 500 unless the error is a route error response).
Errors above the router
A root route ErrorBoundary only covers work inside the router. It does not catch errors thrown above the router, including inside sku’s always-on SkuProvider (see the tree on Providers).
Failures at that level fall through to Express. They are hard to turn into a stylised error page for readers — your route ErrorBoundary never gets a chance to render.
Mount isomorphic and fallible providers in your root layout so the route boundary can cover them.
See also
- Routing — page modules and route tree
- Providers —
SkuProvidersits outside the router - Data loading — loaders and
data()responses
