Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Web Error Handling Error Boundaries

ASecurity

Error boundary patterns, fallback UI, reset/retry, react-error-boundary library, React 19 createRoot error hooks

24 stars
0 votes
0 copies
0 views
Added 5/29/2026
ai-agentstypescriptgoreacttestingapi

Works with

cliapi

Security Analysis

A100/100

Pro scans all 9 files and shows the line behind each finding

Scanned 9/21/2026

$npx -y skills add agents-inc/skills --skill web-error-handling-error-boundaries --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Web Error Handling Error Boundaries?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Web Error Handling Error Boundaries
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/agents-inc-web-error-handling-error-boundaries/badge)](https://www.skillsdirectory.com/skills/agents-inc-web-error-handling-error-boundaries)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: web-error-handling-error-boundaries
description: Error boundary patterns, fallback UI, reset/retry, react-error-boundary library, React 19 createRoot error hooks
---

# React Error Boundaries

> **Quick Guide:** A boundary catches errors thrown during render, in lifecycle methods and in constructors, and swaps the subtree for fallback UI. It never sees event-handler, async or server-render errors — those reach it only when something calls `showBoundary()`. Boundaries are class components, because `getDerivedStateFromError` and `componentDidCatch` have no hook equivalent. React 19 adds `onCaughtError`, `onUncaughtError` and `onRecoverableError` on `createRoot`, which log rather than render and are silently ignored on React 18.

**Detailed Resources:**

- [examples/core.md](examples/core.md) — the class boundary, `react-error-boundary` usage, `resetKeys`, `useErrorBoundary`, granular placement
- [examples/react-19-hooks.md](examples/react-19-hooks.md) — `createRoot`/`hydrateRoot` error options, `captureOwnerStack()`, error filtering
- [examples/recovery.md](examples/recovery.md) — retry limits, exponential backoff, error classification
- [examples/testing.md](examples/testing.md) — what makes a boundary testable, and the fixtures that do it
- [reference.md](reference.md) — what boundaries catch, lifecycle and prop tables, checklists

---

## Which path applies

- **No boundary dependency wanted** — write the class yourself; `getDerivedStateFromError` plus
  `componentDidCatch` is the whole API, and [examples/core.md](examples/core.md) has it in full.
- **`react-error-boundary` is available** — take `resetKeys`, `useErrorBoundary` and the
  `FallbackProps` type rather than reimplementing them, and follow
  [examples/core.md](examples/core.md).
- **React 19, and the question is logging rather than UI** — the three `createRoot` options report
  every error including the ones no boundary caught; see
  [examples/react-19-hooks.md](examples/react-19-hooks.md).

---

<critical_requirements>

## Before writing error boundary code

**Return new state from `getDerivedStateFromError` and put every side effect in `componentDidCatch`.** The first runs during render, where a fetch or a log call breaks React's phase rules; the second runs at commit, where they are safe.

**Wrap each feature area in its own boundary as well as the root.** A single root boundary turns one failing widget into a blank page, and the fallback can say what failed only when it sits beside the thing that failed.

**Give the fallback a way back — a reset callback, `resetKeys`, or both.** Without one the only recovery a user has is a full page reload, which costs them everything they had typed.

**Put `role="alert"` on the fallback and make its controls real buttons.** The subtree vanishing is silent otherwise, and a screen reader user gets no announcement that anything went wrong.

**Route async and event-handler failures through `showBoundary()`.** A boundary cannot see a rejected promise, so an unhandled one leaves the UI showing stale content with no error state at all.

</critical_requirements>

---

**Auto-detection:** error boundary, ErrorBoundary, getDerivedStateFromError, componentDidCatch, fallback UI, react-error-boundary, useErrorBoundary, showBoundary, error fallback, onCaughtError, onUncaughtError, onRecoverableError, captureOwnerStack, FallbackProps, resetKeys

**Applies to:**

- Catching render-phase errors and showing fallback UI in their place
- Reset and retry after a caught error, including retry limits and backoff
- Deciding where boundaries go and how coarse each one should be
- Centralised error reporting from the React root

**Handled elsewhere:**

- Errors thrown in server rendering — the rendering framework decides what a failed render sends to the client, and no client boundary is mounted yet.
- Request failures in a data layer — a boundary sees them only if something rethrows or calls `showBoundary()`; retry and cache invalidation belong to whatever fetches.
- Field-level validation feedback — an invalid form field is expected input, so it renders inline rather than replacing the subtree.
- The monitoring destination — `onError` and the root handlers hand you an error and a component stack, and where those go is the reporting tool's concern.

---

<philosophy>

## Philosophy

A render error that no boundary catches unmounts the entire tree: React tears the root down rather
than leave a half-rendered document on screen, so one thrown error anywhere becomes a blank page.

A boundary buys **isolation** against that: the blast radius is the subtree the nearest boundary
wraps, so where the boundaries sit decides how much of the page a single bug costs. That makes
placement the real decision — recovery, fallback wording and logging all follow from it.

Boundaries do not replace `try`/`catch`; they cover the one region `try`/`catch` cannot reach, which
is React's own render.

</philosophy>

---

<patterns>

## Core patterns

### Pattern 1: Class-based boundary

The two lifecycle methods split by phase: `getDerivedStateFromError` is pure and returns state,
`componentDidCatch` is where reporting goes.

```typescript
static getDerivedStateFromError(error: Error): State {
  return { hasError: true, error };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
  this.props.onError?.(error, errorInfo);
}
```

Full code: [examples/core.md](examples/core.md)

### Pattern 2: `react-error-boundary`

A `FallbackComponent` receives `error` and `resetErrorBoundary`, so the retry control lives wherever
the design wants it. `onError` keeps reporting out of the fallback.

```typescript
<ErrorBoundary FallbackComponent={ErrorFallback} onError={report}>
  <Dashboard />
</ErrorBoundary>;

function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <div role="alert">
      <p>{error.message}</p>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}
```

The prop table is in [reference.md](reference.md); full code in [examples/core.md](examples/core.md).

### Pattern 3: `showBoundary()` for async failures

An async throw never reaches a boundary on its own. `useErrorBoundary` hands you the trigger.

```typescript
const { showBoundary } = useErrorBoundary();

const load = async () => {
  try {
    const response = await fetch(endpoint);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
  } catch (error) {
    showBoundary(error);
  }
};
```

Use it where the failure should replace the subtree. Leave it alone where the error has inline UI of
its own, such as a field-level validation message.

Full code: [examples/core.md](examples/core.md)

### Pattern 4: `resetKeys` for automatic reset

Changing any listed value clears the error and re-renders the children, which is what navigation and
record-switching want.

```typescript
<ErrorBoundary FallbackComponent={ErrorFallback} resetKeys={[currentPath]}>
  <PageContent path={currentPath} />
</ErrorBoundary>
```

Comparison is shallow, so an object or array key needs a stable reference or the boundary resets on
every render.

### Pattern 5: Granular placement

Each widget gets its own boundary and its own fallback text; the root boundary catches whatever the
inner ones do not.

```typescript
<ErrorBoundary fallback={<p>Chart unavailable</p>} onError={report}>
  <ChartWidget />
</ErrorBoundary>
<ErrorBoundary fallback={<p>Table unavailable</p>} onError={report}>
  <DataTable />
</ErrorBoundary>
```

One boundary around all three widgets means the first failure takes the other two with it.

There is an upper bound: the unit is the feature area a user would recognise as having failed on its
own. A boundary around every component adds class components and fallback text nobody reads, and
splits one failure into a page of small broken panels rather than one honest message.

Full code: [examples/core.md](examples/core.md)

### Pattern 6: Fallback UI

The fallback is UI a user meets at their worst moment: announce it, offer a way out, and keep the
stack trace for development.

```typescript
<div role="alert">
  <h2>Something went wrong</h2>
  {isDevelopment && <pre>{error.message}</pre>}
  <button onClick={resetErrorBoundary}>Try again</button>
</div>
```

A `<span onClick>` retry is unreachable by keyboard, and a raw stack in production leaks internals.

Full code: [examples/core.md](examples/core.md)

### Pattern 7: React 19 root error options

`createRoot` takes three handlers that report rather than render, including for errors no boundary
caught. They complement boundaries rather than replacing them.

```typescript
const root = createRoot(container, {
  onCaughtError: (error, info) => report("caught", error, info.componentStack),
  onUncaughtError: (error, info) =>
    report("uncaught", error, info.componentStack),
  onRecoverableError: (error, info) =>
    report("recoverable", error, info.componentStack),
});
```

Full code: [examples/react-19-hooks.md](examples/react-19-hooks.md)

</patterns>

---

<red_flags>

## Red flags

**Breaks at runtime:**

- Side effects in `getDerivedStateFromError` — it runs during render, so a fetch or a `setState` there breaks React's phase rules — report from `componentDidCatch` instead.
- A boundary wrapping itself — a boundary never catches its own render error, and the throw escapes to the parent boundary or to the root — keep the fallback trivial.
- An unstable `resetKeys` entry — the shallow compare sees a new array or object every render and resets the boundary continuously — memoise the value or key on a primitive.
- `<span onClick={reset}>` as the retry control — not focusable and not activated by Enter or Space — use `<button>`.

**Surprising behaviour:**

- Async and event-handler throws never reach a boundary; without `showBoundary()` they vanish.
- The innermost boundary wins, so a wide root fallback appears only when every inner one was missed.
- SSR hydration errors surface as recoverable rather than caught, and a client boundary may never see them.
- Development hot reload trips boundaries that production never would.
- `onCaughtError` runs after the boundary's own `componentDidCatch`, not before it.
- `onRecoverableError` often carries the original throw on `error.cause`.
- `captureOwnerStack()` returns `null` outside development.
- The three root options are silently ignored on React 18 — no warning, no error, no logging.

</red_flags>

Attribution

agents-incagents-inc
View sourceSee grades on GitHubMore from agents-inc →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698621 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →