LEARN · DEBUGGING GUIDE

React Native Reanimated Crash: Debugging Native Module and Worklet Failures

Reanimated crashes often stem from mismatched native modules, improper worklet usage, or metro bundler caching. This guide walks through diagnosing the exact failure and applying targeted fixes.

AdvancedMobile7 min read

What this usually means

Reanimated relies on a native module (JSI) that must be correctly linked and in sync with the JavaScript bundle. A crash typically means the native library is missing, the wrong architecture is loaded, or a worklet function is being executed on the wrong thread. The most common hidden cause is a version mismatch between `react-native-reanimated` and `react-native` (especially after upgrades), or a corrupted metro cache that serves stale JavaScript bytecode with outdated worklet references.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run `npx react-native info` and check the versions of `react-native-reanimated` and `react-native` — ensure they are compatible (see Reanimated docs for version matrix).
  • 2Clear metro cache: `npx react-native start --reset-cache` then rebuild the app.
  • 3On iOS: `cd ios && pod deintegrate && pod install --repo-update` to re-link the native module.
  • 4On Android: check `android/app/build.gradle` for `missingDimensionStrategy 'react-native-camera', 'general'` — not needed but ensure Reanimated's native lib is included.
  • 5Run the app with Chrome debugger disconnected — Reanimated worklets don't work with remote JS debugging (use Flipper or Hermes debugger instead).
  • 6Check the device architecture: on iOS simulators, ensure you build for `arm64` (Apple Silicon) or `x86_64` (Intel) — Reanimated 2.x+ supports both.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • search`node_modules/react-native-reanimated/package.json` — check the installed version against the React Native version.
  • search`ios/Podfile.lock` — look for `react-native-reanimated` pod version and ensure it matches package.json.
  • search`android/app/build.gradle` — verify `implementation project(':react-native-reanimated')` is present.
  • searchMetro bundler logs (terminal running `npx react-native start`) — look for `HMR bundle` errors or `Unable to resolve module` for Reanimated internals.
  • searchXcode crash logs (Window > Organizer > Crashes) — filter by `Reanimated` or `JSI` for native stack traces.
  • search`android/app/src/main/java/com/.../MainApplication.java` — confirm `import com.swmansion.reanimated.ReanimatedPackage;` and `packages.add(new ReanimatedPackage());` are present.
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningVersion mismatch between `react-native-reanimated` and `react-native` (e.g., Reanimated 2.x with RN 0.64 vs 0.68).
  • warningStale metro cache holding outdated worklet transforms after a Reanimated upgrade.
  • warningMissing `babel-plugin-reanimated` in `babel.config.js` — the plugin is required to transform worklet functions.
  • warningUsing remote JS debugging (Chrome DevTools) — Reanimated worklets run on the UI thread and crash when debugger is attached.
  • warningIncorrect pod installation for iOS (missing `use_frameworks!` or `:modular_headers => true` for Reanimated).
  • warningHermes engine incompatibility — some Reanimated versions don't support Hermes (check docs).
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildUpgrade or downgrade `react-native-reanimated` to match the React Native version per the official compatibility table.
  • buildRun `npx react-native start --reset-cache` and rebuild the app (`npx react-native run-ios --reset-cache`).
  • buildAdd `plugins: ['react-native-reanimated/plugin']` to `babel.config.js` and clear cache.
  • buildOn iOS: add `:modular_headers => true` to the Reanimated pod in `Podfile`: `pod 'react-native-reanimated', :path => '../node_modules/react-native-reanimated', :modular_headers => true`.
  • buildDisconnect remote JS debugging — use Flipper or Hermes debugger for Reanimated apps.
  • buildFor Android: add `packagingOptions { pickFirst '**/libc++_shared.so' }` in `android/app/build.gradle` to resolve DSO conflicts.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedRun the app and navigate to a screen that uses `useAnimatedStyle` — the animation should run without crash.
  • verifiedCheck Metro logs for any `[Reanimated]` error messages — should be clean.
  • verifiedOn iOS: build with `xcodebuild` and check for `reanimated` in the linking phase logs.
  • verifiedRun `adb logcat -s ReactNative:V Reanimated:V` on Android and verify no `FATAL EXCEPTION` related to `reanimated`.
  • verifiedToggle between foreground and background — ensure no crash on app state change.
  • verifiedTest on a physical device (not just simulator) to rule out architecture issues.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDon't use `npx react-native upgrade` without checking Reanimated compatibility — it often breaks native modules.
  • warningDon't ignore the `babel.config.js` — forgetting the Reanimated plugin is a top cause.
  • warningDon't use Chrome debugger for development — always use Flipper or Hermes debugger for Reanimated apps.
  • warningDon't manually edit `MainApplication.java` for auto-linked modules — let autolinking handle it unless you're sure.
  • warningDon't assume `pod install` alone fixes native linking — sometimes you need `pod deintegrate` first.
  • warningDon't mix multiple versions of Reanimated across dependencies — check transitive dependencies.
( 07 )War story

Blank screen after Reanimated 2.3 upgrade on iOS 15

Senior Mobile EngineerReact Native 0.66.4, react-native-reanimated 2.3.1, CocoaPods 1.11.3

Timeline

  1. 09:15Upgraded Reanimated from 2.2.0 to 2.3.1 via yarn.
  2. 09:20Ran `npx react-native run-ios` — app launches to white screen, no crash.
  3. 09:25Checked Metro logs — saw `[Reanimated] Mismatch between JavaScript and native side`.
  4. 09:30Cleared cache and rebuilt — same error.
  5. 09:35Opened Xcode, ran the app — console showed `[Reanimated] Failed to create worklet runtime`.
  6. 09:40Checked `Podfile.lock` — noticed `react-native-reanimated` pod version was still 2.2.0.
  7. 09:45Ran `cd ios && pod update react-native-reanimated` — pod updated to 2.3.1.
  8. 09:50Rebuilt app — crash gone, animations working.

I upgraded Reanimated from 2.2.0 to 2.3.1 to get the new layout animations API. After running `yarn add react-native-reanimated@2.3.1`, I started the app on an iOS 15 simulator. The app launched but showed a blank white screen — no error dialog, no crash. I checked the Metro bundler logs and saw the dreaded `[Reanimated] Mismatch between JavaScript and native side` message. This usually means the JS bundle has one version of Reanimated, but the native library is a different version.

I cleared metro cache with `--reset-cache` and rebuilt, but the error persisted. Then I opened Xcode and ran the app from there. In the Xcode console, I saw `[Reanimated] Failed to create worklet runtime`. That narrowed it down to a native linking issue. I checked `ios/Podfile.lock` and found that the `react-native-reanimated` pod was still at 2.2.0 — the pod hadn't been updated even though the JS package was updated.

I ran `cd ios && pod update react-native-reanimated` to force the pod to 2.3.1. After that, I rebuilt the app and the blank screen was gone. The animations worked perfectly. The lesson: always run `pod install` or `pod update` after upgrading a native module, and double-check `Podfile.lock` when you see a version mismatch error.

Root cause

The CocoaPods pod for react-native-reanimated was not updated after upgrading the npm package, causing a version mismatch between JS and native side.

The fix

Run `cd ios && pod update react-native-reanimated` to sync the pod version with the npm package.

The lesson

Always run `pod install` after upgrading native modules, and verify the pod version in `Podfile.lock` matches the npm version.

( 08 )Understanding the JSI Bridge and Worklet Runtime

Reanimated 2+ uses JSI (JavaScript Interface) instead of the traditional bridge to communicate between the JS thread and the UI thread. This allows worklets — functions that run synchronously on the UI thread — to avoid crossing the bridge for every frame. When the native module fails to load or mismatches, the worklet runtime can't be created, causing a crash or blank screen.

The JSI module is initialized in native code (both iOS and Android) and must match the JavaScript bundle's version. If you upgrade the npm package but not the native pod (iOS) or the AAR (Android), the native side will be outdated and the JSI initialization will fail. This is why the error message explicitly says 'Mismatch between JavaScript and native side'.

( 09 )Metro Cache and Worklet Transforms

Reanimated uses a Babel plugin (`react-native-reanimated/plugin`) to transform worklet functions into serializable code that can be sent to the UI thread. This plugin must be added to `babel.config.js`. If you forget it, worklets will not be transformed and will throw `_WORKLET is not defined` errors at runtime.

A corrupted metro cache can also cause issues. The cache stores the transformed JavaScript, and if the Reanimated plugin version changes (e.g., after an upgrade), the cached transforms may be stale. Running `npx react-native start --reset-cache` forces metro to re-transform all modules, including worklets.

( 10 )iOS Pod Installation Pitfalls

CocoaPods integration for Reanimated can be tricky. Common issues include missing `:modular_headers => true` and `use_frameworks!` conflicts. Reanimated 2.x requires modular headers to be enabled for the pod. If you see linking errors like `'reanimated/Tools/ReanimatedFeatures.h' file not found`, add `:modular_headers => true` to the pod line in your `Podfile`.

Another issue is the `use_frameworks!` flag. If your project uses `use_frameworks!`, it can cause duplicate symbol errors with Reanimated. In that case, you may need to use `use_frameworks! :linkage => :static` or avoid `use_frameworks!` altogether.

( 11 )Android Native Module Loading and DSO Conflicts

On Android, Reanimated loads a native shared library (`libreanimated.so`). If you see `UnsatisfiedLinkError`, it means the library wasn't bundled or couldn't be loaded. This can happen if you have multiple architectures (e.g., `arm64-v8a` and `armeabi-v7a`) and there's a conflict. Adding `packagingOptions { pickFirst '**/libc++_shared.so' }` in `android/app/build.gradle` often resolves DSO conflicts.

Also ensure that `react-native-reanimated` is correctly linked. For React Native 0.60+, autolinking should handle it, but if you have manual linking, check `MainApplication.java` for the `ReanimatedPackage` import and addition.

Frequently asked questions

Why does Reanimated crash only in release builds but not debug?

In debug mode, Metro serves the JS bundle from the dev server, and the Reanimated plugin transforms worklets on the fly. In release builds, the bundle is pre-compiled. If the Babel plugin isn't properly configured or the metro cache is stale, the release bundle may contain untransformed worklets that crash on the UI thread. Always test release builds after upgrading Reanimated.

Can I use Reanimated with Expo?

Yes, but with caveats. In Expo managed workflow, you need to use the `expo-dev-client` to include custom native modules like Reanimated. Expo SDK 44+ includes Reanimated 2.3.0 by default. If you encounter crashes, ensure your Expo SDK version matches the Reanimated version. For bare workflow, follow the same steps as vanilla React Native.

What does 'Mismatch between JavaScript and native side' mean exactly?

This error is thrown when the JavaScript bundle's Reanimated version number doesn't match the native module's version. The native side exports a version string, and the JS side compares it. If they differ, Reanimated refuses to initialize to prevent runtime inconsistencies. This typically happens after an npm upgrade without a corresponding native rebuild.

How do I check the Reanimated version on the native side?

On iOS, you can inspect the `Podfile.lock` for `react-native-reanimated` version. On Android, check `node_modules/react-native-reanimated/android/build.gradle` for the `version` property. Alternatively, run `npx react-native info` and look for `react-native-reanimated` under `npmPackages`.

Does Reanimated support Hermes?

Yes, Reanimated 2.3+ supports Hermes, but you need to use a compatible version. Reanimated 2.3.0 requires Hermes 0.9.0 or later. If you see `ReferenceError: _WORKLET is not defined` with Hermes, it may be because the Reanimated Hermes bytecode plugin is missing. Add `'react-native-reanimated/plugin'` to `babel.config.js` and clear cache.