React Error Boundaries
Quick Guide: Error boundaries catch JavaScript errors in component trees and display fallback UI. Usereact-error-boundarylibrary (v6+) for production apps. Place boundaries strategically around features, not just root. Boundaries do NOT catch event handler, async, or SSR errors -- useshowBoundary()hook for async. React 19+: UsecreateRootoptions (onCaughtError,onUncaughtError,onRecoverableError) for centralized error logging.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
(You MUST use getDerivedStateFromError for rendering fallback UI - it runs during render phase)
(You MUST use componentDidCatch for side effects like logging - it runs during commit phase)
(You MUST wrap error boundaries around feature sections, not just the app root)
(You MUST provide reset/retry functionality for recoverable errors)
(You MUST use role="alert" on fallback UI for accessibility)
</critical_requirements>
Auto-detection: error boundary, ErrorBoundary, getDerivedStateFromError, componentDidCatch, fallback UI, react-error-boundary, useErrorBoundary, showBoundary, error recovery, error fallback, onCaughtError, onUncaughtError, onRecoverableError, captureOwnerStack, FallbackProps, resetKeys
When to use:
- Catching and displaying fallback UI for render errors
- Implementing retry/reset functionality after errors
- Preventing entire app crashes from component failures
- Creating isolated failure domains for different features
Key patterns covered:
- Class-based error boundary implementation
react-error-boundarylibrary patterns (v6+)useErrorBoundaryhook withshowBoundary()for async errors- Fallback UI with reset functionality and
role="alert" - Strategic boundary placement (granular vs coarse)
resetKeysfor automatic boundary reset- React 19+:
createRooterror options for centralized logging - React 19+:
captureOwnerStack()for enhanced debugging
When NOT to use:
- Event handler errors (use try/catch)
- Async code errors outside components (use try/catch or showBoundary)
- Server-side rendering errors (handle at framework level)
- API request errors (handle in your data fetching layer)
Detailed Resources:
- [examples/core.md](examples/core.md) - Complete boundary implementations, library usage, granular placement
- [examples/react-19-hooks.md](examples/react-19-hooks.md) - createRoot error options, captureOwnerStack, error filtering
- [examples/recovery.md](examples/recovery.md) - Retry limits, exponential backoff, error classification
- [examples/testing.md](examples/testing.md) - Testing boundaries, async errors, resetKeys
- [reference.md](reference.md) - Decision frameworks, anti-patterns, checklists
<philosophy>
Philosophy
Error boundaries provide graceful degradation -- when one component fails, the rest of the application continues working. The key principle is isolation: wrap distinct features in separate boundaries so failures are contained. Error boundaries are the ONLY way to catch errors during React rendering; they complement try/catch for imperative code.
Core principles:
- Isolation over global handling - Multiple granular boundaries beat one root boundary
- Recovery over failure - Provide reset/retry when possible
- User feedback over silent failure - Show meaningful, accessible fallback UI
- Logging integration - Pass errors to monitoring via
onErrorcallback - Centralized observability (React 19+) - Use
createRooterror options for unified error tracking
</philosophy>
<patterns>
Core Patterns
Pattern 1: Class-Based Error Boundary (Native React)
Error boundaries MUST be class components -- getDerivedStateFromError and componentDidCatch have no hook equivalents.
Two Lifecycle Methods
| Method | Phase | Purpose | Side Effects | | -------------------------- | ------ | ----------------------------- | ------------ | | getDerivedStateFromError | Render | Update state to show fallback | NOT allowed | | componentDidCatch | Commit | Log errors, call callbacks | Allowed |
// ✅ Good - Complete error boundary with reset
import { Component } from "react";
import type { ErrorInfo, ReactNode } from "react";
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
onError?: (error: Error, errorInfo: ErrorInfo) => void;
onReset?: () => void;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
this.props.onError?.(error, errorInfo);
}
handleReset = (): void => {
this.props.onReset?.();
this.setState({ hasError: false, error: null });
};
render(): ReactNode {
const { hasError, error } = this.state;
const { children, fallback } = this.props;
if (hasError && error) {
if (typeof fallback === "function") return fallback(error, this.handleReset);
if (fallback) return fallback;
return (
<div role="alert">
<h2>Something went wrong</h2>
<button onClick={this.handleReset}>Try again</button>
</div>
);
}
return children;
}
}
Why good: Render-phase/commit-phase separation, reset capability, flexible fallback API, onError enables logging without coupling to specific tools
Pattern 2: react-error-boundary Library (v6+)
Production-ready error boundary with hooks support, resetKeys, and useErrorBoundary.
npm install react-error-boundary
| Prop | Type | Purpose | | ------------------- | ----------------------- | ------------------------------- | | fallback | ReactNode | Static fallback UI | | FallbackComponent | ComponentType | Component that renders fallback | | fallbackRender | (props) => ReactNode | Render prop for fallback | | onError | (error, info) => void | Error logging callback | | onReset | (details) => void | Called when boundary resets | | resetKeys | unknown[] | Dependencies that trigger reset |
// ✅ Good - FallbackComponent pattern
import { ErrorBoundary } from "react-error-boundary";
import type { FallbackProps } from "react-error-boundary";
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<div role="alert">
<h2>Something went wrong</h2>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
export function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, info) => {
// Send to your error monitoring service
console.error("Boundary caught:", error, info);
}}
>
<Dashboard />
</ErrorBoundary>
);
}
Why good: Reusable FallbackComponent, onError decouples logging, onReset enables state cleanup
See [examples/core.md](examples/core.md) for resetKeys, useErrorBoundary, and granular placement examples.
Pattern 3: useErrorBoundary Hook (Async Errors)
Error boundaries don't catch async errors. Use showBoundary() from useErrorBoundary to manually trigger the nearest boundary.
//