@stackra/error
v2.0.0
Published
Error-boundary system for the Stackra framework — app/route/component boundaries, default HeroUI fallbacks, imperative escalation, and contract-based FATAL logging.
Maintainers
Readme
@stackra/error
Error-boundary system for the Stackra framework.
Catch render-time failures at the app, route, and component level; show sensible
default fallbacks built on @stackra/ui; and log everything at FATAL through
the LOGGER_MANAGER contract — without a hard dependency on @stackra/logger.
Entry points
| Import | Contents |
| ------------------------ | ----------------------------------------------------------------------------------------------- |
| @stackra/error | Framework-agnostic helpers — normalizeError, serializeError, SerializedError. |
| @stackra/error/react | Boundaries, presets, fallbacks, useErrorBoundary, withErrorBoundary. |
| @stackra/error/router | RouteErrorBoundary — React Router errorElement integration. |
| @stackra/error/native | NativeErrorModule, NativeErrorBoundary, NativeErrorFallback, InlineNativeErrorFallback. |
| @stackra/error/testing | In-memory recorder + MockFallback + createMockErrorBoundary for consumer tests. |
Quick start
import { AppErrorBoundary, ComponentErrorBoundary } from "@stackra/error/react";
function App() {
return (
<AppErrorBoundary>
<Dashboard />
<ComponentErrorBoundary label="Activity feed unavailable.">
<ActivityFeed />
</ComponentErrorBoundary>
</AppErrorBoundary>
);
}Escalate async failures
import { useErrorBoundary } from "@stackra/error/react";
function SaveButton() {
const { showBoundary } = useErrorBoundary();
return (
<button
onClick={async () => {
try {
await save();
} catch (err) {
showBoundary(err);
}
}}
>
Save
</button>
);
}React Router
import { RouteErrorBoundary } from "@stackra/error/router";
const routes = [
{ path: "/", element: <Home />, errorElement: <RouteErrorBoundary /> },
];React Native
The ./native subpath ships the React Native counterpart — a full-screen HeroUI
Native fallback, an inline widget-level fallback, and a class-based
NativeErrorBoundary that resolves its reporter through DI so caught errors
route through @stackra/logger's LOGGER_MANAGER at fatal level.
Mount NativeErrorModule.forRoot(...) once at the app root — then wrap any
subtree in <NativeErrorBoundary>:
import { NativeLoggerModule } from "@stackra/logger/native";
import { Module } from "@stackra/container";
import { NativeErrorBoundary, NativeErrorModule } from "@stackra/error/native";
import { SafeAreaProvider } from "react-native-safe-area-context";
@Module({
imports: [
// Mount the logger BEFORE the error module so its
// `LOGGER_MANAGER` binding is available when the reporter's
// constructor resolves.
NativeLoggerModule.forRoot({ default: "console" }),
NativeErrorModule.forRoot({
// Namespace boundary crashes in your log aggregator.
loggerContext: "MyApp/ErrorBoundary",
}),
],
})
export class AppModule {}
// Wrap the app tree. SafeAreaProvider is required by the fallback
// because it uses SafeAreaView internally.
export function App() {
return (
<SafeAreaProvider>
<NativeErrorBoundary>
<RootNavigator />
</NativeErrorBoundary>
</SafeAreaProvider>
);
}Widget-level boundaries render the compact inline fallback:
<NativeErrorBoundary variant="inline">
<ActivityFeed />
</NativeErrorBoundary>The boundary skips the auto-report step when no reporter is bound (i.e. when the
consumer skips NativeErrorModule.forRoot()) — you still get the fallback UI,
just no log write. Consumers who want to route errors to their own transport
(Sentry, in-house telemetry) pass a custom implementation:
NativeErrorModule.forRoot({
reporter: {
report({ error, info, boundary }) {
mySentry.captureException(error, { extra: { info, boundary } });
},
},
});JS crash vs native crash
NativeErrorBoundary catches React render errors — same contract as web
boundaries. It does NOT catch:
- Native crashes on the iOS / Android side. Wire those through Sentry-RN or the platform's own crash reporter.
- Async errors inside event handlers or effects. Use
useErrorBoundary().showBoundary(err)— same escalation hook the web subpath ships. (Landing in a follow-up on the native subpath; escalate viathrowinside a render for now.) - Errors during React's initial mount when the boundary itself is inside the crashing subtree. Mount the boundary as high in the tree as possible.
Reporting (logging, analytics, telemetry)
The boundary owns no observability concern. Every boundary exposes an
onError(error, info) callback — wire it to whatever you use (a logger,
analytics, Sentry):
<AppErrorBoundary
onError={(error, info) => logger.fatal("render crash", error, info)}
>
<App />
</AppErrorBoundary>This keeps @stackra/error free of any logger/telemetry dependency; the
consumer decides where errors go.
