|
| 1 | +--- |
| 2 | +title: Unhandled Promise Rejections |
| 3 | +description: "Learn about Sentry's Unhandled Promise Rejections handling in React Native." |
| 4 | +sidebar_order: 60 |
| 5 | +--- |
| 6 | + |
| 7 | +Sentry automatically tracks unhandled promise rejections in React Native applications. Since version `6.15.0` the SDK uses engine-specific implementations to ensure reliable tracking across different JavaScript engines including Hermes, JavaScriptCore (JSC), and React Native Web environments. |
| 8 | + |
| 9 | +## Configuration |
| 10 | + |
| 11 | +Promise rejection tracking is enabled by default when you initialize Sentry. You can control promise rejection tracking through the `reactNativeErrorHandlersIntegration`: |
| 12 | + |
| 13 | +```javascript |
| 14 | +import * as Sentry from '@sentry/react-native'; |
| 15 | + |
| 16 | +Sentry.init({ |
| 17 | + dsn: "___PUBLIC_DSN___", |
| 18 | + integrations: [ |
| 19 | + Sentry.reactNativeErrorHandlersIntegration({ |
| 20 | + onunhandledrejection: false, // Disables promise rejection tracking |
| 21 | + }), |
| 22 | + ], |
| 23 | +}); |
| 24 | +``` |
| 25 | + |
| 26 | +## Engine-Specific Behavior |
| 27 | + |
| 28 | +### Hermes Engine |
| 29 | + |
| 30 | +When using Hermes, Sentry uses the engine's native promise rejection tracking capabilities. |
| 31 | + |
| 32 | +<Alert> |
| 33 | + |
| 34 | +Enabling Hermes rejection tracking will overwrite existing hooks due to limitations of the engine. Only one promise rejection tracker can be active at a time. |
| 35 | + |
| 36 | +</Alert> |
| 37 | + |
| 38 | +### JavaScriptCore (JSC) |
| 39 | + |
| 40 | +For JSC environments, Sentry uses Promise polyfill with rejection tracking capabilities. This approach also overwrites existing hooks. |
| 41 | + |
| 42 | +<Alert> |
| 43 | + |
| 44 | +The Promise polyfill is used to ensure compatibility and provide rejection tracking functionality that may not be available natively in older JSC versions. |
| 45 | + |
| 46 | +</Alert> |
| 47 | + |
| 48 | +### React Native Web |
| 49 | + |
| 50 | +For React Native Web, Sentry leverages the browser's native promise rejection tracking capabilities, providing seamless integration with web debugging tools. |
| 51 | + |
| 52 | +## Multiple Tools and Logging |
| 53 | + |
| 54 | +When using multiple tools for promise rejection tracking, be aware that: |
| 55 | + |
| 56 | +- **Hermes**: Only one rejection tracker can be active. Sentry will take precedence. |
| 57 | +- **JSC**: Sentry's Promise polyfill will override existing handlers. |
| 58 | +- **React Native Web**: Can coexist better with other browser-based debugging tools. |
| 59 | + |
| 60 | +### Example: Using Sentry with Other Debugging Tools |
| 61 | + |
| 62 | +```javascript |
| 63 | +import * as Sentry from '@sentry/react-native'; |
| 64 | + |
| 65 | +// For development, you might want to disable Sentry's tracking |
| 66 | +// to allow other debugging tools to handle promise rejections |
| 67 | +if (__DEV__) { |
| 68 | + Sentry.init({ |
| 69 | + dsn: "___PUBLIC_DSN___", |
| 70 | + integrations: [ |
| 71 | + Sentry.reactNativeErrorHandlersIntegration({ |
| 72 | + onunhandledrejection: false, // Let other tools handle in development |
| 73 | + }), |
| 74 | + ], |
| 75 | + }); |
| 76 | +} else { |
| 77 | + // In production, use Sentry's tracking |
| 78 | + Sentry.init({ |
| 79 | + dsn: "___PUBLIC_DSN___", |
| 80 | + // Default configuration with promise tracking enabled |
| 81 | + }); |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +## Troubleshooting |
| 86 | + |
| 87 | +Due to an issue with React Native's dependencies, unhandled promise rejections might not be correctly caught by Sentry when using the JavaScriptCore (JSC) engine or a React Native SDK version before `6.15.0`. |
| 88 | + |
| 89 | +If the promise rejection handler was not correctly attached, our SDK might issue a warning: |
| 90 | + |
| 91 | +> WARN: Unhandled promise rejections might not be caught by Sentry. Read about how to fix this on our troubleshooting docs. |
| 92 | +
|
| 93 | +Otherwise, we will let you know that the handler is attached: |
| 94 | + |
| 95 | +> [Sentry] Unhandled promise rejections will be caught by Sentry. |
| 96 | +
|
| 97 | +### Auto Patching (Default Behavior) |
| 98 | + |
| 99 | +By default we will patch the global `Promise` instance to ensure it matches exactly with the version that React Native uses. |
| 100 | + |
| 101 | +#### Using With Other Polyfills |
| 102 | + |
| 103 | +If you use a polyfilling library that patches the global `Promise` instance, you'll need to make sure you run the polyfill **after** `Sentry.init` is called. |
| 104 | + |
| 105 | + |
| 106 | +```javascript |
| 107 | +import allSettled from "promise.allsettled"; |
| 108 | + |
| 109 | +Sentry.init({ |
| 110 | + dsn: "___PUBLIC_DSN___", |
| 111 | +}); |
| 112 | +// Any Promise polyfilling must occur AFTER Sentry.init |
| 113 | +// This step globally patches Promise. |
| 114 | +allSettled.shim(); |
| 115 | + |
| 116 | +// Separate core-js example |
| 117 | +import "core-js/stable/promise/all-settled"; |
| 118 | +``` |
| 119 | + |
| 120 | +Your linter might throw some errors here, but this step is necessary. |
| 121 | + |
| 122 | +#### Disable Auto Patching |
| 123 | + |
| 124 | +You can disable the global promise patching by passing `patchGlobalPromise: false` in either `Sentry.init` or the `ReactNativeErrorHandlers` integration. Note that if you disable our auto patching, to ensure that unhandled rejections are still caught, you will need to [manually force a package resolution](#manually-forcing-a-package-resolution). |
| 125 | + |
| 126 | +### Manually Forcing a Package Resolution |
| 127 | + |
| 128 | +You don't need to perform the steps below if you don't disable [auto patching](#auto-patching-default-behavior). You'll need to ensure that the version of `promise` that you use matches exactly with the version that React Native uses. |
| 129 | + |
| 130 | +1. Check the version of `promise` that your version of `react-native` uses. You can do this by going into `node_modules/react-native/package.json` and checking the version there, for example we find that it uses `^8.0.3`: |
| 131 | + |
| 132 | +```json {filename:node_modules/react-native/package.json} |
| 133 | +{ |
| 134 | + "dependencies": { |
| 135 | + // ... |
| 136 | + "promise": "^8.0.3" |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +2. Add a package resolution with the same version as `react-native`'s' to **your** `package.json` file, this will force this version to be used. You will then need to run a fresh `yarn install` or `npm install` to use the package resolution you just added. |
| 142 | + |
| 143 | +```json {filename:package.json} |
| 144 | +{ |
| 145 | + "resolutions": { |
| 146 | + "promise": "^8.0.3" |
| 147 | + } |
| 148 | +} |
| 149 | +``` |
| 150 | + |
| 151 | +<Alert> |
| 152 | + |
| 153 | +Package resolutions are currently only supporred by `yarn`. If you use `npm`, you can use a third-party package called [npm-force-resolutions](https://www.npmjs.com/package/npm-force-resolutions) to achieve this. |
| 154 | + |
| 155 | +</Alert> |
| 156 | + |
| 157 | +3. If the fix is successful, our SDK will no longer display the above warning and will indicate that promise rejections will be caught. |
| 158 | + |
| 159 | + |
| 160 | +## Migration from Older Versions |
| 161 | + |
| 162 | +If you're upgrading from an older version of Sentry React Native: |
| 163 | + |
| 164 | +1. Remove any manual Promise polyfill resolutions from your `package.json` |
| 165 | +2. Remove any custom promise rejection handling code |
| 166 | +3. Update to the latest version of `@sentry/react-native` |
| 167 | +4. Test that promise rejections are being captured correctly |
| 168 | + |
| 169 | +The new engine-specific approach should resolve previous compatibility issues automatically. |
0 commit comments