# Error boundary


The `FlareErrorBoundary` component catches errors during rendering, in lifecycle methods, and in constructors of the component tree below it. When an error is caught, it is automatically reported to Flare with React-specific context including a structured component stack trace.

## Basic usage

Wrap your component tree (or parts of it) in the `FlareErrorBoundary`:

```jsx
import { FlareErrorBoundary } from '@flareapp/react';

function App() {
    return (
        <FlareErrorBoundary>
            <MyComponent />
        </FlareErrorBoundary>
    );
}
```

## Displaying a fallback UI

Without a `fallback` prop, the error boundary renders nothing when an error is caught. The `fallback` prop accepts either a static `ReactNode` or a render function:

```jsx
// Static fallback
<FlareErrorBoundary fallback={<p>Something went wrong.</p>}>
    <App />
</FlareErrorBoundary>
```

The render function receives the caught `error`, the parsed `componentStack` (as a string array), and a `resetErrorBoundary` function to clear the error state:

```jsx
// Render function fallback with error details and reset
<FlareErrorBoundary
    fallback={({ error, componentStack, resetErrorBoundary }) => (
        <div>
            <h2>Something went wrong</h2>
            <p>{error.message}</p>
            <pre>{componentStack.join('\n')}</pre>
            <button onClick={resetErrorBoundary}>Try again</button>
        </div>
    )}
>
    <App />
</FlareErrorBoundary>
```

## Resetting the error boundary

You can automatically reset the error boundary when certain values change using the `resetKeys` prop. When any value in the array changes between renders (compared per-index via `Object.is`), or when the array's length changes, the boundary automatically resets and re-renders its children.

A common use case is resetting the boundary when the user navigates to a different page:

```jsx
function App() {
    const location = useLocation();

    return (
        <FlareErrorBoundary
            resetKeys={[location.pathname]}
            onReset={(error) => {
                console.log('Navigated away from error, previous error:', error?.message);
            }}
            fallback={<p>Something went wrong.</p>}
        >
            <Routes />
        </FlareErrorBoundary>
    );
}
```

The `onReset` callback fires when the error boundary resets (either via `resetErrorBoundary()` from the fallback or via `resetKeys` changing). It receives the previous error, allowing conditional cleanup:

```jsx
// Example using React Query (TanStack Query) to refetch stale data on reset
const queryClient = useQueryClient();

<FlareErrorBoundary
    onReset={(error) => {
        console.log('Recovering from:', error?.message);
        queryClient.invalidateQueries();
    }}
    fallback={({ resetErrorBoundary }) => (
        <button onClick={resetErrorBoundary}>Retry</button>
    )}
>
    <App />
</FlareErrorBoundary>
```

## Lifecycle hooks

The error boundary provides three hooks that fire at different stages of the error reporting lifecycle. The `beforeSubmit` and `afterSubmit` callbacks receive a `context` object with the following shape:

```ts
{
    react: {
        componentStack: string[];            // Formatted component stack lines
        componentStackFrames: {              // Parsed frames with source locations
            component: string;
            file: string | null;
            line: number | null;
            column: number | null;
        }[];
        version?: string;                    // The React version that rendered the error
        minifiedError?: {                    // Present only for a minified production React error
            number: number;
            args: string[];
            url: string | null;
        };
    }
}
```

`minifiedError` is only set when the caught error is one of React's minified production errors (the ones that read "Minified React error #..."). It decodes the error number, its arguments, and the URL to React's full error message, so you don't have to look it up by hand.

These types are exported from `@flareapp/react` as `FlareReactContext` (the full object), `ComponentStackFrame` (a single entry in `componentStackFrames`), and `MinifiedReactError` (the shape of `minifiedError`).

The callbacks themselves are not wrapped in a `try`/`catch`. If a hook throws, the boundary itself will crash, so keep the logic defensive.

### `beforeEvaluate`

Fires **before** the component stack context is built. This is the place to attach custom context, tags, or user information to the Flare report:

```jsx
<FlareErrorBoundary
    beforeEvaluate={({ error, errorInfo }) => {
        flare.addContext('user', { id: currentUser.id });
        flare.addContext('feature-flags', getActiveFlags());
    }}
>
    <App />
</FlareErrorBoundary>
```

### `beforeSubmit`

Fires **after** the component stack context is built but **before** the error is reported to Flare. The callback receives the `context` and must return a (possibly modified) context object. Use this to filter or enrich the report context:

```jsx
<FlareErrorBoundary
    beforeSubmit={({ error, errorInfo, context }) => {
        return {
            ...context,
            react: {
                ...context.react,
                componentStack: context.react.componentStack.filter(
                    (line) => !line.includes('ThirdPartyWrapper'),
                ),
            },
        };
    }}
>
    <App />
</FlareErrorBoundary>
```

### `afterSubmit`

Fires **after** `flare.report()` is called. Note that the report is sent asynchronously, so this callback runs after the report is initiated, not after the network request completes. Use this for side effects like logging to a secondary service, showing a toast, or updating app state:

```jsx
<FlareErrorBoundary
    afterSubmit={({ error, errorInfo, context }) => {
        console.error('Caught by FlareErrorBoundary:', error);
        console.error('Component stack:', errorInfo.componentStack);
        console.error('Reported context:', context);
    }}
>
    <App />
</FlareErrorBoundary>
```

## Filtering errors

The error boundary hooks above are designed for adding context and running side effects; they cannot prevent an error from being reported. To filter or suppress errors, use the core JavaScript client hooks via `flare.configure()`.

Note that the boundary's `beforeEvaluate` and `beforeSubmit` are **different hooks** from `flare.configure({ beforeEvaluate, beforeSubmit })`. They share the same name, but have different signatures and capabilities. The execution order when both are configured is:

1. Boundary `beforeEvaluate` (adds context, cannot suppress)
2. `flare.report()` is called internally, which triggers:
3. Client `beforeEvaluate` via `flare.configure()` (**can** suppress by returning `false`)
4. Client `beforeSubmit` via `flare.configure()` (**can** suppress or modify the report)
5. Report is sent to Flare
6. Boundary `afterSubmit`

To suppress specific errors, use the client-level hooks:

```js
flare.configure({
    beforeEvaluate: (error) => {
        if (error.message.includes('Boring error')) {
            return false; // Don't report this error
        }

        return error;
    },
});
```

See the [client hooks documentation](/docs/javascript/errors/client-hooks) for more details.

## Errors in event handlers

React error boundaries do not catch errors in event handlers (e.g. `onClick`, `onChange`). These errors are caught automatically by the `@flareapp/js` client via `window.onerror`, so they will still be reported to Flare. If you're using React 19, the `onUncaughtError` callback from [`flareReactErrorHandler`](/docs/react/errors/error-handler) also catches these.

## Using your own error boundaries

If you have your own error boundary components (e.g. for displaying a custom fallback UI), the error won't bubble up to Flare's error boundary and won't be reported automatically. You can manually report errors to Flare in your own error boundary. Pass the component stack as context so Flare can display it:

```jsx
import { flare } from '@flareapp/js';

class MyErrorBoundary extends React.Component {
    componentDidCatch(error, errorInfo) {
        flare.report(error, {
            'context.react': {
                componentStack: errorInfo.componentStack,
            },
        });
    }

    render() {
        // your fallback UI
    }
}
```

You can also use a combination of Flare's error boundary at the root of your app and your own error boundaries further down the tree for specific sections.

## Component stack context

When the error boundary catches an error, it parses React's component stack and sends both a formatted string array and structured frames in the report context:

```json
{
  "context": {
    "react": {
      "componentStack": [
        "at ErrorComponent (http://localhost:5173/src/App.tsx:12:9)",
        "at div",
        "at App (http://localhost:5173/src/App.tsx:5:3)"
      ],
      "componentStackFrames": [
        {
          "component": "ErrorComponent",
          "file": "http://localhost:5173/src/App.tsx",
          "line": 12,
          "column": 9
        },
        {
          "component": "div",
          "file": null,
          "line": null,
          "column": null
        },
        {
          "component": "App",
          "file": "http://localhost:5173/src/App.tsx",
          "line": 5,
          "column": 3
        }
      ]
    }
  }
}
```

The structured `componentStackFrames` enable sourcemap resolution and rich dashboard rendering.

## Props reference

| Prop | Type | Description |
|------|------|-------------|
| `flare` | `Flare` | Explicit Flare instance to report through, instead of the default singleton registered by `@flareapp/js`. You only need this outside a normal web setup, for example when using `@flareapp/react/inject`. See the [API reference](/docs/react/reference/api). |
| `fallback` | `ReactNode \| (props) => ReactNode` | UI to display when an error is caught. The render function receives `error`, `componentStack` (string array), and `resetErrorBoundary`. |
| `resetKeys` | `unknown[]` | Values that trigger an automatic reset when changed (compared per-index via `Object.is`, or when the array's length changes). |
| `beforeEvaluate` | `({ error, errorInfo }) => void` | Called before the component stack context is built. `errorInfo` is React's `ErrorInfo` (includes `componentStack`). |
| `beforeSubmit` | `({ error, errorInfo, context }) => FlareReactContext` | Called before submitting. Return a (possibly modified) context. If not provided, the original `context` is used as-is. |
| `afterSubmit` | `({ error, errorInfo, context }) => void` | Called after `flare.report()` is called (the report is sent asynchronously). |
| `onReset` | `(error: Error \| null) => void` | Called when the error boundary is reset; receives the previous error (or `null`). |
