|
2 | 2 | title: React Error Boundary |
3 | 3 | excerpt: '' |
4 | 4 | description: >- |
5 | | - Learn how the React SDK exports an error boundary component that leverages |
6 | | - React component APIs. |
| 5 | + Learn how to use Sentry's ErrorBoundary component to catch React rendering errors |
| 6 | + and display fallback UIs. |
7 | 7 | og_image: /og-images/platforms-javascript-guides-react-features-error-boundary.png |
8 | 8 | --- |
9 | 9 |
|
10 | | -The React SDK exports an error boundary component that leverages [React component APIs](https://reactjs.org/docs/error-boundaries.html) to automatically catch and send JavaScript errors from inside a React component tree to Sentry. |
| 10 | +Sentry's `ErrorBoundary` component catches JavaScript errors in a specific part of your React component tree, sends them to Sentry with React component context, and displays a fallback UI. This page covers when and how to use it. |
11 | 11 |
|
12 | | -## Configure |
| 12 | +## Error Hooks vs ErrorBoundary |
13 | 13 |
|
14 | | -```javascript |
15 | | -import React from "react"; |
16 | | -import * as Sentry from "@sentry/react"; |
| 14 | +React 19 introduced error hooks (`onUncaughtError`, `onCaughtError`, `onRecoverableError`) that capture errors at the root level. Sentry's `reactErrorHandler` integrates with these hooks. So when should you use each? |
17 | 15 |
|
18 | | -<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}> |
19 | | - <Example /> |
20 | | -</Sentry.ErrorBoundary>; |
21 | | -``` |
| 16 | +| Approach | Scope | What It Does | |
| 17 | +|----------|-------|--------------| |
| 18 | +| `reactErrorHandler()` (React 19+) | **Global** — All errors in the app | Reports errors to Sentry. No UI handling. | |
| 19 | +| `ErrorBoundary` | **Specific subtree** — Only wrapped components | Reports errors to Sentry AND renders fallback UI. Allows section-specific handling. | |
22 | 20 |
|
23 | | -The Sentry Error Boundary is also available as a higher order component. |
| 21 | +**In React 19+, they complement each other:** |
| 22 | +- `reactErrorHandler` — Global safety net for error reporting |
| 23 | +- `ErrorBoundary` — Scoped error handling with custom fallbacks and context |
24 | 24 |
|
25 | | -```javascript |
26 | | -import React from "react"; |
| 25 | +**In React 18 and below**, `ErrorBoundary` is your primary tool for both error reporting and UI recovery. |
| 26 | + |
| 27 | +```javascript {filename:main.jsx} |
27 | 28 | import * as Sentry from "@sentry/react"; |
| 29 | +import { createRoot } from "react-dom/client"; |
| 30 | + |
| 31 | +const root = createRoot(document.getElementById("root"), { |
| 32 | + // Error reporting: captures all errors |
| 33 | + onUncaughtError: Sentry.reactErrorHandler(), |
| 34 | + onCaughtError: Sentry.reactErrorHandler(), |
| 35 | + onRecoverableError: Sentry.reactErrorHandler(), |
| 36 | +}); |
28 | 37 |
|
29 | | -Sentry.withErrorBoundary(Example, { fallback: <p>an error has occurred</p> }); |
| 38 | +root.render(<App />); |
30 | 39 | ``` |
31 | 40 |
|
32 | | -<Alert level="warning" title="Note"> |
| 41 | +Then use `ErrorBoundary` for section-specific fallback UIs: |
33 | 42 |
|
34 | | -In development mode, React will rethrow errors caught within an error boundary to the global error handler. This will result in Sentry only reporting an error from the global error handler, but not from the error boundary itself. We recommend testing the error boundary with a production build of React. |
| 43 | +```javascript {filename:App.jsx} |
| 44 | +function App() { |
| 45 | + return ( |
| 46 | + <Layout> |
| 47 | + <Sentry.ErrorBoundary fallback={<DashboardError />}> |
| 48 | + <Dashboard /> |
| 49 | + </Sentry.ErrorBoundary> |
| 50 | + </Layout> |
| 51 | + ); |
| 52 | +} |
| 53 | +``` |
35 | 54 |
|
36 | | -</Alert> |
| 55 | +## Basic Usage |
37 | 56 |
|
38 | | -In the example below, when the `<Example />` component hits an error, the `<Sentry.ErrorBoundary>` component will send data about that error and the component tree to Sentry, open a user feedback dialog, and render a fallback UI. |
| 57 | +Wrap components that might fail with `ErrorBoundary` to prevent the entire app from crashing: |
39 | 58 |
|
40 | 59 | ```javascript |
41 | | -import React from "react"; |
42 | 60 | import * as Sentry from "@sentry/react"; |
43 | 61 |
|
44 | | -import { Example } from "../example"; |
45 | | - |
46 | | -function FallbackComponent() { |
47 | | - return <div>An error has occurred</div>; |
48 | | -} |
49 | | - |
50 | | -const myFallback = <FallbackComponent />; |
51 | | -// Alternatively: |
52 | | -// const myFallback = () => <FallbackComponent />; |
53 | | - |
54 | | -class App extends React.Component { |
55 | | - render() { |
56 | | - return ( |
57 | | - <Sentry.ErrorBoundary fallback={myFallback} showDialog> |
58 | | - <Example /> |
59 | | - </Sentry.ErrorBoundary> |
60 | | - ); |
61 | | - } |
| 62 | +function App() { |
| 63 | + return ( |
| 64 | + <Sentry.ErrorBoundary fallback={<p>Something went wrong</p>}> |
| 65 | + <Dashboard /> |
| 66 | + </Sentry.ErrorBoundary> |
| 67 | + ); |
62 | 68 | } |
63 | | - |
64 | | -export default App; |
65 | 69 | ``` |
66 | 70 |
|
67 | | -<Alert level="warning" title="Note"> |
| 71 | +When `Dashboard` (or any child) throws an error: |
| 72 | +1. Sentry captures the error with the React component stack |
| 73 | +2. The fallback UI renders instead of the crashed component |
| 74 | +3. The rest of your app continues working |
68 | 75 |
|
69 | | -By default React [logs all errors to the console](https://github.com/facebook/react/blob/493f72b0a7111b601c16b8ad8bc2649d82c184a0/packages/react-reconciler/src/ReactFiberErrorLogger.js#L85), even if you are using a React error boundary. If you are using the `CaptureConsole` integration this means that Sentry will capture the error through the `CaptureConsole` integration and not through the error boundary. |
| 76 | +### Higher-Order Component |
70 | 77 |
|
71 | | -</Alert> |
| 78 | +You can also use the HOC pattern: |
72 | 79 |
|
73 | | -## Linked Errors |
| 80 | +```javascript |
| 81 | +import * as Sentry from "@sentry/react"; |
74 | 82 |
|
75 | | -In [React v17 and above](https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks), the SDK will automatically parse the [error boundary `componentStack`](https://react.dev/reference/react/Component#componentdidcatch-parameters) and attach the full stacktrace to the event via `error.cause`. This requires the [`LinkedErrors`](../../configuration/integrations/linkederrors/) integration to be enabled (enabled by default). To get the full source context, we recommend setting up [source maps](../../sourcemaps) for your project. |
| 83 | +const DashboardWithBoundary = Sentry.withErrorBoundary(Dashboard, { |
| 84 | + fallback: <p>Something went wrong</p>, |
| 85 | +}); |
| 86 | +``` |
76 | 87 |
|
77 | | - |
| 88 | +## Fallback UI Options |
78 | 89 |
|
79 | | -## Options |
| 90 | +The `fallback` prop accepts a React element or a function that receives error details: |
80 | 91 |
|
81 | | -The ErrorBoundary component exposes a variety of props that can be passed in for extra configuration. There are no required options, but we highly recommend that you set a fallback component. |
| 92 | +```javascript {filename:App.jsx} |
| 93 | +import * as Sentry from "@sentry/react"; |
82 | 94 |
|
83 | | -`showDialog` (boolean) |
| 95 | +function App() { |
| 96 | + return ( |
| 97 | + <Sentry.ErrorBoundary |
| 98 | + fallback={({ error, componentStack, resetError }) => ( |
| 99 | + <div> |
| 100 | + <h2>Something went wrong</h2> |
| 101 | + <details> |
| 102 | + <summary>Error details</summary> |
| 103 | + <pre>{error.toString()}</pre> |
| 104 | + <pre>{componentStack}</pre> |
| 105 | + </details> |
| 106 | + <button onClick={resetError}>Try again</button> |
| 107 | + </div> |
| 108 | + )} |
| 109 | + > |
| 110 | + <Dashboard /> |
| 111 | + </Sentry.ErrorBoundary> |
| 112 | + ); |
| 113 | +} |
| 114 | +``` |
84 | 115 |
|
85 | | -If a [Sentry User Feedback Widget](../../user-feedback/) should be rendered when the Error Boundary catches an error. |
| 116 | +The function receives: |
| 117 | +- `error` — The error that was thrown |
| 118 | +- `componentStack` — React's component stack trace |
| 119 | +- `resetError` — Function to reset the boundary and retry rendering |
86 | 120 |
|
87 | | -`dialogOptions` (Object) |
| 121 | +## Multiple Boundaries |
88 | 122 |
|
89 | | -Options that are passed into the Sentry User Feedback Widget. See all possible customization options [here](../../user-feedback/#customizing-the-widget). |
| 123 | +Use multiple boundaries to isolate failures and provide context-specific fallbacks: |
90 | 124 |
|
91 | | -`fallback` (React.ReactNode or Function) |
| 125 | +```javascript {filename:App.jsx} |
| 126 | +import * as Sentry from "@sentry/react"; |
92 | 127 |
|
93 | | -A React element to render when the error boundary catches an error. Can be an actual React element (i.e. `<Fallback />`), or a function that returns a React element. If you provide a function, Sentry will call it with additional info and helpers (see example below). |
| 128 | +function App() { |
| 129 | + return ( |
| 130 | + <Layout> |
| 131 | + {/* Sidebar failure doesn't affect main content */} |
| 132 | + <Sentry.ErrorBoundary |
| 133 | + fallback={<SidebarError />} |
| 134 | + beforeCapture={(scope) => scope.setTag("section", "sidebar")} |
| 135 | + > |
| 136 | + <Sidebar /> |
| 137 | + </Sentry.ErrorBoundary> |
94 | 138 |
|
95 | | -`onError` (Function) |
| 139 | + {/* Main content failure doesn't affect sidebar */} |
| 140 | + <Sentry.ErrorBoundary |
| 141 | + fallback={<ContentError />} |
| 142 | + beforeCapture={(scope) => scope.setTag("section", "content")} |
| 143 | + > |
| 144 | + <MainContent /> |
| 145 | + </Sentry.ErrorBoundary> |
| 146 | + </Layout> |
| 147 | + ); |
| 148 | +} |
| 149 | +``` |
96 | 150 |
|
97 | | -A function that gets called when the Error Boundary encounters an error. `onError` is useful if you want to propagate the error into a state management library like Redux, or if you want to check any side effects that could have occurred due to the error. |
| 151 | +Use `beforeCapture` to tag errors by section — this helps filter and group errors in Sentry. |
98 | 152 |
|
99 | | -`onMount` (Function) |
| 153 | +## Options Reference |
100 | 154 |
|
101 | | -A function that gets called on ErrorBoundary `componentDidMount()`. |
| 155 | +| Prop | Type | Description | |
| 156 | +|------|------|-------------| |
| 157 | +| `fallback` | ReactNode \| Function | UI to render when an error is caught. Function receives `{ error, componentStack, resetError }` | |
| 158 | +| `showDialog` | boolean | Show the [Sentry User Feedback Widget](../../user-feedback/) when an error occurs | |
| 159 | +| `dialogOptions` | Object | Options for the feedback widget. See [customization options](../../user-feedback/#customizing-the-widget) | |
| 160 | +| `onError` | Function | Called when an error is caught. Useful for propagating to state management | |
| 161 | +| `beforeCapture` | Function | Called before sending to Sentry. Use to add tags or context | |
| 162 | +| `onMount` | Function | Called on `componentDidMount()` | |
| 163 | +| `onUnmount` | Function | Called on `componentWillUnmount()` | |
102 | 164 |
|
103 | | -`onUnmount` (Function) |
| 165 | +## Linked Errors |
104 | 166 |
|
105 | | -A function that gets called on ErrorBoundary `componentWillUnmount()`. |
| 167 | +In React v17 and above, Sentry automatically parses the [error boundary `componentStack`](https://react.dev/reference/react/Component#componentdidcatch-parameters) and attaches it to the error via `error.cause`. This requires the [`LinkedErrors`](../../configuration/integrations/linkederrors/) integration (enabled by default). |
106 | 168 |
|
107 | | -`beforeCapture` (Function) |
| 169 | +For readable stack traces, set up [source maps](../../sourcemaps). |
108 | 170 |
|
109 | | -_(Available in version 5.20.0 and above)_ |
| 171 | +## Custom Error Boundaries |
110 | 172 |
|
111 | | -A function that gets called before an error is sent to Sentry, allowing for extra tags or context to be added to the error. |
| 173 | +If you need a custom error boundary, use `Sentry.captureReactException` to maintain the linked component stack: |
112 | 174 |
|
113 | | -## Examples |
| 175 | +<Alert> |
114 | 176 |
|
115 | | -#### Setting a Fallback Function (Render Props) |
| 177 | +Custom error boundaries **must be class components** — this is a React requirement, not a Sentry limitation. |
116 | 178 |
|
117 | | -Below is an example where a fallback prop, using the [render props approach](https://reactjs.org/docs/render-props.html), is used to display a fallback UI on error. The fallback UI returns to a standard component state when reset using the `resetError()` API provided by the component through render props. |
| 179 | +</Alert> |
118 | 180 |
|
119 | | -```javascript |
| 181 | +```javascript {filename:CustomErrorBoundary.jsx} |
120 | 182 | import React from "react"; |
121 | 183 | import * as Sentry from "@sentry/react"; |
122 | 184 |
|
123 | | -class App extends React.Component { |
124 | | - constructor(props) { |
125 | | - super(props); |
126 | | - this.state = { |
127 | | - message: "This is my app", |
128 | | - }; |
| 185 | +class CustomErrorBoundary extends React.Component { |
| 186 | + state = { hasError: false }; |
| 187 | + |
| 188 | + static getDerivedStateFromError() { |
| 189 | + return { hasError: true }; |
| 190 | + } |
| 191 | + |
| 192 | + componentDidCatch(error, info) { |
| 193 | + // Captures error with React component stack |
| 194 | + Sentry.captureReactException(error, info); |
129 | 195 | } |
130 | 196 |
|
131 | 197 | render() { |
132 | | - return ( |
133 | | - <Sentry.ErrorBoundary |
134 | | - fallback={({ error, componentStack, resetError }) => ( |
135 | | - <React.Fragment> |
136 | | - <div>You have encountered an error</div> |
137 | | - <div>{error.toString()}</div> |
138 | | - <div>{componentStack}</div> |
139 | | - <button |
140 | | - onClick={() => { |
141 | | - this.setState({ message: "This is my app" }); |
142 | | - { |
143 | | - /* When resetError() is called it will remove the Fallback component */ |
144 | | - } |
145 | | - { |
146 | | - /* and render the Sentry ErrorBoundary's children in their initial state */ |
147 | | - } |
148 | | - resetError(); |
149 | | - }} |
150 | | - > |
151 | | - Click here to reset! |
152 | | - </button> |
153 | | - </React.Fragment> |
154 | | - )} |
155 | | - > |
156 | | - <div>{this.state.message}</div> |
157 | | - {/* on click, this button sets an Object as a message, not a string. */} |
158 | | - {/* which will cause an error to occur in the component tree */} |
159 | | - <button |
160 | | - onClick={() => this.setState({ message: { text: "Hello World" } })} |
161 | | - > |
162 | | - Click here to change message! |
163 | | - </button> |
164 | | - </Sentry.ErrorBoundary> |
165 | | - ); |
| 198 | + if (this.state.hasError) { |
| 199 | + return this.props.fallback; |
| 200 | + } |
| 201 | + return this.props.children; |
166 | 202 | } |
167 | 203 | } |
168 | | - |
169 | | -export default App; |
170 | 204 | ``` |
171 | 205 |
|
172 | | -#### Using multiple error boundaries |
| 206 | +<Alert level="info"> |
173 | 207 |
|
174 | | -When using multiple error boundaries, we recommend using `beforeCapture` to set tags/context so that you can tell which error boundary the error occurred from. In the example below, we attach tags to errors based on what route they rendered in. |
| 208 | +`Sentry.captureReactException` requires SDK version 9.8.0 or above. |
175 | 209 |
|
176 | | -```javascript |
177 | | -import React from "react"; |
178 | | -import * as Sentry from "@sentry/react"; |
| 210 | +</Alert> |
179 | 211 |
|
180 | | -function App({ props }) { |
181 | | - return ( |
182 | | - <React.Fragment> |
183 | | - <Sentry.ErrorBoundary |
184 | | - beforeCapture={(scope) => { |
185 | | - scope.setTag("location", "first"); |
186 | | - scope.setTag("anotherTag", "anotherValue"); |
187 | | - }} |
188 | | - > |
189 | | - <Route to="path/to/first" component={First} /> |
190 | | - </Sentry.ErrorBoundary> |
191 | | - <Sentry.ErrorBoundary |
192 | | - beforeCapture={(scope) => { |
193 | | - scope.setTag("location", "second"); |
194 | | - }} |
195 | | - > |
196 | | - <Route to="path/to/second" component={Second} /> |
197 | | - </Sentry.ErrorBoundary> |
198 | | - </React.Fragment> |
199 | | - ); |
200 | | -} |
| 212 | +## Quick Reference |
201 | 213 |
|
202 | | -export default App; |
203 | | -``` |
| 214 | +| Scenario | Solution | |
| 215 | +|----------|----------| |
| 216 | +| React 19+: Global error reporting | Use `reactErrorHandler()` in `createRoot` options | |
| 217 | +| Scoped error handling with fallback UI | Wrap with `<Sentry.ErrorBoundary>` | |
| 218 | +| Tag errors by app section | Use `beforeCapture` prop on `ErrorBoundary` | |
| 219 | +| React 18 and below: Error reporting + fallback | Use `<Sentry.ErrorBoundary>` (handles both) | |
| 220 | +| Custom boundary with Sentry integration | Use `captureReactException` in `componentDidCatch` | |
204 | 221 |
|
205 | | -## Manually Capturing Errors |
| 222 | +## Troubleshooting |
206 | 223 |
|
207 | | -If you don't want to use the Sentry Error Boundary component, you can use the `captureReactException` function to capture errors manually with your own Error Boundary. This will still ensure that the `componentStack` is linked to the error as detailed in the [Linked Errors](#linked-errors) section. The `Sentry.captureReactException` function requires React SDK `v9.8.0` or above. |
| 224 | +### Errors Reported Twice |
208 | 225 |
|
209 | | -```javascript |
210 | | -import * as Sentry from "@sentry/react"; |
| 226 | +In development mode, React rethrows errors caught by error boundaries to the global handler. This may result in duplicate reports. **Test with a production build** to verify behavior. |
211 | 227 |
|
212 | | -class ErrorBoundary extends React.Component { |
213 | | - componentDidCatch(error, info) { |
214 | | - Sentry.captureReactException(error, info); |
215 | | - } |
| 228 | +### CaptureConsole Conflicts |
216 | 229 |
|
217 | | - render() { |
218 | | - return this.props.children; |
219 | | - } |
220 | | -} |
221 | | -``` |
| 230 | +React [logs caught errors to the console](https://github.com/facebook/react/blob/493f72b0a7111b601c16b8ad8bc2649d82c184a0/packages/react-reconciler/src/ReactFiberErrorLogger.js#L85). If you're using the `CaptureConsole` integration, errors may be captured through that integration instead of the error boundary. |
222 | 231 |
|
223 | | -## Next Steps: |
| 232 | +### Missing Component Stack |
224 | 233 |
|
225 | | -- [Return to **Getting Started**](../../) |
226 | | -- [Return to the main components page](../) |
| 234 | +If you don't see the React component stack: |
| 235 | +1. Ensure you're using React 17 or above |
| 236 | +2. Verify the `LinkedErrors` integration is enabled (it is by default) |
| 237 | +3. Set up [source maps](../../sourcemaps) for readable traces |
0 commit comments