Skip to content

Commit 4667fc1

Browse files
authored
docs(react-native): Document GlobalErrorBoundary for fatal non-render errors (#17392)
## DESCRIBE YOUR PR Documents the new `Sentry.GlobalErrorBoundary` component shipping in [getsentry/sentry-react-native#6023](getsentry/sentry-react-native#6023) / [#5930](getsentry/sentry-react-native#5930). ## IS YOUR CHANGE URGENT? - [ ] Urgent deadline (GA date, etc.): - [ ] Other deadline: - [x] None: Not urgent, can wait up to 1 week+ This can land alongside or after the SDK release that ships `GlobalErrorBoundary`. ## PRE-MERGE CHECKLIST - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) ## LEGAL BOILERPLATE Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. ## EXTRA RESOURCES - [Sentry Docs contributor guide](https://docs.sentry.io/contributing/)
1 parent b480952 commit 4667fc1

1 file changed

Lines changed: 84 additions & 52 deletions

File tree

docs/platforms/react-native/integrations/error-boundary.mdx

Lines changed: 84 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The React Native SDK exports an error boundary component that uses [React compon
1212

1313
<Alert level="warning" title="Render errors only">
1414

15-
React error boundaries **only catch errors during rendering, in lifecycle methods, and in constructors**. They do **not** catch errors in event handlers, asynchronous code (`setTimeout`, `Promise`), or native errors. See [Handling Non-Render Errors](#handling-non-render-errors) for how to handle those.
15+
React error boundaries **only catch errors during rendering, in lifecycle methods, and in constructors**. They do **not** catch errors in event handlers, asynchronous code (`setTimeout`, `Promise`), or native errors. For a fallback UI that covers those cases too, use [`Sentry.GlobalErrorBoundary`](#showing-a-fallback-ui-for-fatal-errors).
1616

1717
</Alert>
1818

@@ -102,7 +102,7 @@ In [React v17 and above](https://reactjs.org/blog/2020/08/10/react-v17-rc.html#n
102102

103103
Errors in event handlers, `async` functions, `setTimeout`, and other non-render code won't be caught by `ErrorBoundary`. This is a [React limitation](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary), not specific to Sentry.
104104

105-
Sentry's [`reactNativeErrorHandlersIntegration`](/platforms/react-native/integrations/default/#reactnativeerrorhandlersintegration) (enabled by default) **automatically reports** these errors to Sentry — you don't need to do anything extra for error reporting. However, it won't display a fallback UI.
105+
Sentry's [`reactNativeErrorHandlersIntegration`](/platforms/react-native/integrations/default/#reactnativeerrorhandlersintegration) (enabled by default) **automatically reports** these errors to Sentry — you don't need to do anything extra for error reporting. For a fallback UI on fatal non-render errors, use [`Sentry.GlobalErrorBoundary`](#showing-a-fallback-ui-for-fatal-errors).
106106

107107
### Component-Level Error Handling
108108

@@ -138,74 +138,94 @@ function MyComponent() {
138138
}
139139
```
140140

141-
### Global Error Handling With Fallback UI
141+
### Showing a Fallback UI for Fatal Errors
142142

143-
To show a fallback UI for **any** unhandled JavaScript error (not just render errors), you can create a provider that listens to React Native's global error handler and combines it with `ErrorBoundary`:
143+
To show a fallback UI for fatal JavaScript errors that are thrown **outside** the React render tree — event handlers, `setTimeout`, async code, and errors routed through `ErrorUtils` — wrap your app in `Sentry.GlobalErrorBoundary`:
144144

145145
```javascript
146-
import React, { useState, useEffect } from "react";
147-
import { Button, DeviceEventEmitter, Text, View } from "react-native";
146+
import React from "react";
147+
import { Button, Text, View } from "react-native";
148148
import * as Sentry from "@sentry/react-native";
149149

150-
// Set up the global error listener before Sentry.init()
151-
const globalHandler = global.ErrorUtils?.getGlobalHandler();
152-
global.ErrorUtils?.setGlobalHandler((error, isFatal) => {
153-
DeviceEventEmitter.emit("GLOBAL_UNHANDLED_ERROR", error);
154-
155-
// Call the default handler in development for the React Native red box.
156-
// In production, we skip the default handler to prevent the app from
157-
// crashing so the fallback UI can be shown instead.
158-
if (__DEV__ && globalHandler) {
159-
globalHandler(error, isFatal);
160-
}
161-
});
162-
163-
Sentry.init({
164-
dsn: "___PUBLIC_DSN___",
165-
});
166-
167-
function GlobalFallback({ onReset }) {
150+
function App() {
168151
return (
169-
<View>
170-
<Text>Something went wrong.</Text>
171-
<Button onPress={onReset} title="Restart" />
172-
</View>
152+
<Sentry.GlobalErrorBoundary
153+
fallback={({ error, eventId, resetError }) => (
154+
<View>
155+
<Text>Something went wrong.</Text>
156+
<Text>{error?.message}</Text>
157+
<Text>Event ID: {eventId}</Text>
158+
<Button onPress={resetError} title="Restart" />
159+
</View>
160+
)}
161+
>
162+
<RestOfYourApp />
163+
</Sentry.GlobalErrorBoundary>
173164
);
174165
}
166+
```
175167
176-
function AppErrorProvider({ children }) {
177-
const [globalError, setGlobalError] = useState(null);
168+
`GlobalErrorBoundary` is a superset of `ErrorBoundary`: it catches everything `ErrorBoundary` catches **and** fatal non-rendering errors routed through React Native's `ErrorUtils` global handler. The error is captured through Sentry's normal pipeline (with the correct `mechanism` and `fatal` level) before the fallback is rendered — no duplicate events, no need to call `Sentry.captureException` yourself.
178169
179-
useEffect(() => {
180-
const subscription = DeviceEventEmitter.addListener(
181-
"GLOBAL_UNHANDLED_ERROR",
182-
(error) => setGlobalError(error)
183-
);
184-
return () => subscription.remove();
185-
}, []);
170+
In release builds, `GlobalErrorBoundary` takes over React Native's default fatal handler so the fallback can own the screen instead of the app being torn down. In development, LogBox still appears — the fallback renders alongside it.
186171
187-
if (globalError) {
188-
return <GlobalFallback onReset={() => setGlobalError(null)} />;
189-
}
172+
#### Opt-In Options
190173
191-
return (
192-
<Sentry.ErrorBoundary
193-
fallback={({ resetError }) => (
194-
<GlobalFallback onReset={resetError} />
195-
)}
196-
>
197-
{children}
198-
</Sentry.ErrorBoundary>
199-
);
200-
}
174+
By default, only fatal errors trigger the fallback. Two props extend coverage:
175+
176+
```javascript
177+
<Sentry.GlobalErrorBoundary
178+
// Also render the fallback for non-fatal ErrorUtils errors
179+
includeNonFatalGlobalErrors
180+
// Also render the fallback for unhandled promise rejections
181+
includeUnhandledRejections
182+
fallback={/* ... */}
183+
>
184+
<App />
185+
</Sentry.GlobalErrorBoundary>
201186
```
202187
203-
<Alert level="info" title="Note">
188+
Most apps should leave both off: non-fatals are often recoverable, and unhandled rejections are frequently surfaced as toasts or inline errors rather than as a full-screen fallback.
204189
205-
When intercepting the global error handler, unhandled errors will still be reported to Sentry by the `reactNativeErrorHandlersIntegration`. You do **not** need to call `Sentry.captureException` manually in the global handler.
190+
#### HOC Alternative
191+
192+
```javascript
193+
import * as Sentry from "@sentry/react-native";
194+
195+
export default Sentry.withGlobalErrorBoundary(App, {
196+
fallback: ({ error, resetError }) => (
197+
<Fallback error={error} onRetry={resetError} />
198+
),
199+
});
200+
```
201+
202+
<Alert level="info" title="Reset semantics">
203+
204+
`resetError()` clears the fallback and remounts the children, but it does **not** restore JavaScript state that was corrupted by the error. Use `onReset` to navigate to a safe screen, reload data, or reset your state container.
206205
207206
</Alert>
208207
208+
#### Migration From a Hand-Rolled `setGlobalHandler`
209+
210+
Before `GlobalErrorBoundary`, showing a fallback for non-render errors required overriding `ErrorUtils.setGlobalHandler`, bridging through `DeviceEventEmitter`, and combining with `ErrorBoundary`. This is **no longer recommended** — the manual approach bypasses Sentry's flush and fatal deduplication, risks running the app in a corrupted state, and is fragile across React Native versions.
211+
212+
```javascript
213+
// ❌ Before: manual global handler + ErrorBoundary
214+
const defaultHandler = global.ErrorUtils?.getGlobalHandler();
215+
global.ErrorUtils?.setGlobalHandler((error, isFatal) => {
216+
DeviceEventEmitter.emit("GLOBAL_UNHANDLED_ERROR", error);
217+
if (__DEV__) defaultHandler?.(error, isFatal);
218+
});
219+
// ...plus a provider subscribing to the event and an ErrorBoundary
220+
221+
// ✅ After: one component
222+
<Sentry.GlobalErrorBoundary fallback={/* ... */}>
223+
<App />
224+
</Sentry.GlobalErrorBoundary>
225+
```
226+
227+
If you previously disabled the `onerror` integration to avoid duplicate reports, re-enable it (or remove the `reactNativeErrorHandlersIntegration({ onerror: false })` override) — `GlobalErrorBoundary` relies on it for capture.
228+
209229
## Options
210230
211231
The ErrorBoundary component exposes a variety of props that can be passed in for extra configuration. There aren't any required options, but we highly recommend setting a fallback component.
@@ -230,6 +250,18 @@ A function that gets called on ErrorBoundary `componentWillUnmount()`.
230250
231251
A function that gets called before an error is sent to Sentry, allowing for extra tags or context to be added to the error.
232252
253+
### `GlobalErrorBoundary`-Only Options
254+
255+
`GlobalErrorBoundary` accepts every `ErrorBoundary` option above plus:
256+
257+
`includeNonFatalGlobalErrors` (boolean, default `false`)
258+
259+
Also render the fallback when a non-fatal error is reported through `ErrorUtils`. Off by default to match the semantics of React Native's native red-screen, which only appears for fatals.
260+
261+
`includeUnhandledRejections` (boolean, default `false`)
262+
263+
Also render the fallback when an unhandled promise rejection occurs. Off by default because many apps prefer to surface rejections as toasts or inline errors rather than as a full-screen fallback.
264+
233265
## Examples
234266
235267
### Setting a Fallback Function (Render Props)

0 commit comments

Comments
 (0)