One morning I launched a Rork-generated app exactly the way I always do, and was greeted by an unfamiliar red screen:
TurboModuleRegistry.getEnforcing(...): 'RNSomeModule' could not be found.
Verify that a module by this name is registered in the native binary.
I had not touched a single line of JavaScript. Tracing it back, the trigger was the New Architecture (Fabric / TurboModules) becoming the default in Expo SDK 53 and later. Plenty of people are stuck on this same screen, so here is the isolation routine I settled on while migrating six wallpaper apps to the New Architecture.
What the error is actually saying
getEnforcing means "a native module with this name must exist, so go find it." Its sibling get returns null when nothing turns up, but getEnforcing throws immediately if the module is missing.
So this error is telling you: "JavaScript tried to call the native module RNSomeModule, but the native binary currently running on the device has no module registered under that name." The key insight is that the problem lives in the native binary, not in your JS. Miss that, and you can rewrite JavaScript all day without getting anywhere.
In my experience the cause almost always collapses into one of four buckets.
Cause 1: You're running inside Expo Go
This is the most common one. Expo Go is an app that ships with a fixed, predetermined set of native modules. Any library you added — react-native-mmkv, a billing SDK, your own native module — simply does not exist inside Expo Go.
Checking is easy: look at how you launched.
# Goes through Expo Go -> your custom native modules won't run
npx expo start
# What you actually need -> a dev build that includes your modules
npx expo start --dev-clientThe fix is to make a development build.
# Add expo-dev-client
npx expo install expo-dev-client
# Produce a dev build that runs on the device (cloud build example)
eas build --profile development --platform iosThink of a development build as "Expo Go rebaked with your exact set of libraries." Once it is installed, your JS changes keep hot-reloading just like before.
Cause 2: You updated JS but never rebuilt the native side
This often hits right after you npm install a library that contains native code. Installing the new library that provides RNSomeModule does nothing to the binary already on your device — it is still the old one, with no record of the new module. Only the JS bundle moved forward; the native side never caught up.
You need a native rebuild.
# Regenerate the native projects first
npx expo prebuild --clean
# Reinstall Pods on iOS
cd ios && pod install && cd ..
# Build again from native
npx expo run:iosWhen "I fixed and saved my JS but it still breaks," you have usually skipped the native rebuild. Whenever you add or update a library, remember to rebuild rather than reload — it saves a surprising amount of wasted time.
Cause 3: The library isn't New Architecture-ready
If the error survives a clean rebuild from prebuild --clean, the library itself may not support TurboModules yet. Older libraries are written against the legacy Bridge, and the New Architecture runs in bridgeless mode where they can't be resolved as TurboModules.
First, pin down which library is responsible. Take the module name from the error (the RNSomeModule part) and cross-reference it against the library's README and React Native Directory to see whether New Architecture support is listed.
If a compatible release exists, update.
npx expo install react-native-some-module@latestIf no compatible version exists yet, temporarily turning the New Architecture off is the pragmatic move. Set this in app.json:
{
"expo": {
"newArchEnabled": false
}
}After changing it, always rebuild starting from npx expo prebuild --clean. Editing app.json alone changes nothing. Treat this as buying time, not a permanent fix. During my own migration I replaced incompatible libraries one at a time, then flipped newArchEnabled back on once they were all sorted.
Cause 4: Wrong module name or a flawed custom spec
If you write native modules yourself, the spec name fed to Codegen and the name registered in the native implementation can drift apart. If you call getEnforcing('Foo') but the implementation registers itself as Bar, of course it won't be found. Make sure three places agree: the spec file name (e.g. NativeFoo.ts), the registration name in @ReactModule / RCT_EXPORT_MODULE, and the call site.
A quick isolation order
When in doubt, knock these down from the top — it's the fastest path.
- Are you on Expo Go? (-> switch to a dev build)
- Did you rebuild natively after adding the library? (-> rebake from
prebuild --clean) - Is the library New Architecture-ready? (-> check the Directory; if not, temporarily set
newArchEnabled: false) - For a custom module, do the registration names match?
Steps 1 and 2 resolve the majority of cases. Only once you reach step 3 should you start suspecting library compatibility.
Avoiding the same rut
Migrating to the New Architecture all at once, across every app, makes isolation hard. Of my six apps, I migrated the one with the fewest dependencies first, nailed down the routine above, then rolled it out to the rest. Surfacing the sticking points on app number one made apps two through six finish remarkably quietly.
When the error appears, the first thing to recall is: this is a native-binary problem, not a JavaScript problem. Hold onto that, and the fix will fit into one of the four drawers we laid out today. I hope it saves someone else from stalling on the same screen.