Global error component#
One component, declared once, for every failure a route decided not to handle locally.
Use it when several exception codes deserve the same screen, or as the backstop for unexpected errors. Not when a specific failure needs its own UI — renderComponent(...) in the route's handler is more precise. See Route exception handling.
When a route exception handler delegates to globalError(), the outlet renders one application-wide error component and feeds it the exception. That component can read all of its possible exceptions — typed and exhaustive — because the codes routed to it are mirrored in a global registry maintained automatically by ESLint.
Register the component#
Pass withErrorComponent(...) directly to provideCraftRouter(...) (mixed with your router features):
provideCraftRouter(
appRoutes.toRoutes(),
withComponentInputBinding(),
withErrorComponent({
component: MyGlobalErrorScreen,
componentDeps:
{} as import('./my-global-error-screen').GenDeps_MyGlobalErrorScreen,
}),
),
It also works standalone via provideCraftLoading(withErrorComponent({ component, componentDeps })).
Consume the exception#
export const MyGlobalErrorScreen = craftComponent(
'MyGlobalErrorScreen',
{},
function* () {
// Signal<USER_DISABLED | HttpError | …>
const error = yield* CraftGlobalError();
const message = computed(() => {
switch (error()?.code) {
case 'USER_DISABLED':
return 'This account is disabled.';
default:
return 'Something went wrong.';
}
});
return div(h1(() => message()));
},
);
CraftGlobalError() is typed as the union of every exception any route delegates to the global component, so switch (error().code) is exhaustively typed. The outlet writes the active exception into CRAFT_GLOBAL_ERROR just before rendering the component.
The registry (auto-maintained)#
The union comes from CraftGlobalExceptionRegistry, keyed by route path and code:
declare module '@craft-ts/core' {
interface CraftGlobalExceptionRegistry {
'user/:userId': {
USER_DISABLED: CraftRouteExceptionType<
typeof demoRoutes,
'user/:userId',
'USER_DISABLED'
>;
HttpError: CraftRouteExceptionType<
typeof demoRoutes,
'user/:userId',
'HttpError'
>;
};
}
}
Do not edit this block by hand. The craft-ts/global-exception-registry-match ESLint rule detects every handleExceptions handler that calls globalError() and keeps the registry in sync:
npx nx lint demo --fix
A missing entry is reported as an error; --fix inserts the [path][code] entry. CraftRouteExceptionType resolves the typed exception object for a code on a route from the collection's route definitions (no type checker required — the rule builds the reference from the collection variable and the path/code literals).
The screen itself still needs an armed RouteExceptionComponentCheckedDI in app.config.ts. Architecture tests fail if that proof is missing.
Default behaviour#
If no withErrorComponent is configured, globalError() and unhandled thrown errors leave the outlet in its error state without a component. Provide a global error component to render a fallback UI.
See Also#
Route exception handling — where
globalError()is returnedArchitecture rules —
assertRouteDiProofskeeps the error-screen proof armed