# Fix "Unable to resolve module", "Cannot find native module", "main" has not been registered, and Other React Native Redbox Errors

> Unable to resolve module, Cannot find native module, "main" has not been registered, No script URL provided: what each React Native and Expo redbox means and how to fix it.

- Author: Ike Studios LLC
- Published: 2026-10-08
- Canonical: https://ceraph.dev/blog/react-native-redbox-errors

---

You hit run, the app opens, and the screen goes red: **"No script URL provided. Make sure the packager is running or you have embedded a JS bundle in your application bundle. unsanitizedScriptURLString = (null)."** Or its siblings: **"Could not connect to development server."** On Android, **"Unable to load script."** Mid-session, **"Disconnected from Metro."** After installing a package, **"Cannot find native module"** or **"TurboModuleRegistry.getEnforcing(...): '…' could not be found."** And before your first screen renders, **"main" has not been registered.**

Or the bundle never builds at all: **"Unable to resolve module."**

These messages often point to startup, network, or native-build configuration problems. Their causes can also include incorrect module names or application setup. Below: what each one means, the manual fix, and which ones Ceraph handles before your AI coding agent ever sees them.

Ceraph is an [MCP](https://modelcontextprotocol.io) server that lets your coding agent drive and test your React Native or Expo app on iOS devices and simulators, plus Android devices and emulators. Getting the app running and connected is the first thing it does, so it has to handle every error below.

## "No script URL provided" (unsanitizedScriptURLString = (null))

**What it means:** this is the iOS message. The app launched and asked for its JavaScript bundle, but it had no URL to load from. In a debug build, that usually means Metro wasn't running or wasn't ready yet when the app asked. Metro's first compile after a cold start can take a while, so the app wins the race and gives up. In a release build, it means no bundle was embedded in the app.

**Manual fix:** start Metro (`npx expo start` or `npx react-native start`), wait for the first bundle to finish compiling, then reload the app. For a release build, confirm the bundle is generated and included in the app target.

**What Ceraph does:** `ceraph_start` sequences bring-up so a development build doesn't ask for its bundle before Metro can serve it, which prevents the race in the common case. If a development build still lands on this redbox, `ceraph_start` recognizes it and recovers on its own: it reopens an Expo development build on this project's Metro, and reloads or relaunches a bare React Native app onto the warm bundle. It only reports the recovery once it has re-read the screen and confirmed the redbox is gone. If the redbox persists, Ceraph doesn't claim a recovery it didn't make: it reports the redbox to your agent and says to reload manually or check the Metro logs.

## "Could not connect to development server"

**What it means:** the app knows where Metro should be but can't reach it. The redbox lists the usual suspects: the server isn't running, the URL is wrong, or the device isn't on the same network as your computer. A phone on a different Wi-Fi network, or one that blocks device-to-device traffic, produces it every time.

**Manual fix:** make sure Metro is running, put the device and the computer on the same network, and for Android over USB, run `adb reverse tcp:8081 tcp:8081` so the device's `localhost:8081` reaches your computer.

**What Ceraph does:** on iOS, this is one of the startup redboxes `ceraph_start` recovers from automatically, the same as above, in Expo development builds and bare React Native apps alike. On a physical iPhone, Ceraph also confirms the phone actually loaded and ran the bundle. A green build isn't enough. If the phone can't reach Metro over the network and it's connected with a USB data cable, Ceraph re-routes the app over USB and checks again. Otherwise it returns remediation instead of handing your agent a stranded app.

## Android: "Unable to load script"

**What it means:** the Android counterpart: *"Unable to load script. Make sure you're running Metro or that your bundle 'index.android.bundle' is packaged correctly for release."* The device must be USB-connected with the bundler at `localhost:8081`, or on the same Wi-Fi as your computer.

**Manual fix:** run Metro, run `adb reverse tcp:8081 tcp:8081` for a USB device, or point the dev settings at your computer's IP on the same network. For a release build, check that the bundle is packaged.

**What Ceraph does:** on Android, `ceraph_start` sets up the device-to-Metro route itself (`adb reverse`) on devices and emulators. It connects the app to this project's Metro, opening an Expo development build on it directly and mapping a bare React Native app's port to it over ADB, then confirms the app's JavaScript is running. It won't report ready over a redbox or a LogBox error. If a previous session left the app on a connection redbox, Ceraph reconnects it and requires a clean screen; if it can't get one, `ceraph_start` fails with the step that broke instead of reporting ready.

## "Disconnected from Metro" and "Reload to reconnect"

**What it means:** the app loaded fine, then lost its connection to Metro. You restarted the bundler, your laptop slept, the network changed, or the phone locked. React Native shows *"Disconnected from Metro."* or *"Metro has restarted since the last edit. Reload to reconnect."* and the app keeps running stale code until someone reloads it.

**Manual fix:** reload the app (press `r` in the Metro terminal, or use the dev menu).

**What Ceraph does:** Fast Reload is on by default. When Metro comes back after a disconnect from a Metro restart, a network change, or the host waking from sleep, Ceraph reloads the development build so it reconnects to a fresh bundle. A reload resets in-memory state, and native changes still need a rebuild. You can turn it off with the `fastReload` preference or `CERAPH_FAST_RELOAD=false`.

## "Cannot find native module" and "TurboModuleRegistry.getEnforcing(...) could not be found"

**What it means:** your JavaScript is calling native code that isn't in the binary on the device. Expo modules report it as *"Cannot find native module '…'"*. Other libraries on the New Architecture report *"TurboModuleRegistry.getEnforcing(...): '…' could not be found. Verify that a module by this name is registered in the native binary."* You added a package with native code (an `expo-*` module, a camera library) or changed a config plugin, and the installed build predates it. Expo Go can't load custom native modules at all, which is why a development build is required.

**Manual fix:** rebuild the native app (`npx expo run:ios` / `npx expo run:android`, or a new EAS development build). If the native folders are stale, `npx expo prebuild --clean` regenerates them, but it deletes any manual native edits.

**What Ceraph does:** `ceraph_start` fingerprints what goes into your native build (resolved native packages, autolinking and config plugin inputs, `Podfile.lock`, and the native project configuration) and rebuilds before testing when the installed build is behind it, in Expo and bare React Native projects alike. Your agent can run the same check directly with `rn_check_prebuild`. On the iOS Simulator, Ceraph also catches the nastier case where a build reports success but an Expo module never made it into the app. If the app still throws one of these errors, `rn_get_errors` returns it with the module name, so your agent can tell a missing rebuild from a misspelled or uninstalled package. If a native-module launch failure persists, `ceraph_start({ rebuild: true })` forces a rebuild that keeps your existing `ios/` and `android/` folders.

## "main" has not been registered

**What it means:** the bundle loaded, but nothing registered the app's root component under the name the native side asked for, usually `main` in Expo apps. React Native names the two usual causes in the redbox itself: *"Metro (the local dev server) is run from the wrong folder"*, or *"A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called."* In the second case, this redbox is a symptom; the real error happened earlier, while your modules were loading.

**Manual fix:** check that Metro is running from this project's root, then scroll back through the Metro logs for the first error, usually a failed import or an exception thrown at module load, and fix that. If you changed the entry file or the registered name, make sure the `AppRegistry.registerComponent` name matches what the native app expects.

**What Ceraph does:** Ceraph only uses a Metro it can confirm is serving this project and points your app at it, which rules out the wrong-folder case (see the next section). For the load-time error, the agent doesn't have to dig through Metro output. Ceraph captures errors from the moment your entry file starts running, so `rn_get_errors` returns the original exception or bundler error, and `ceraph_start` won't report ready while it's on screen. Your agent fixes the cause instead of the symptom.

## The wrong app's bundle loads

**What it means:** React Native projects default Metro to port 8081. If another project's Metro already holds it, your app connects there and renders the other project's code, or fails in confusing ways.

**Manual fix:** stop the other Metro, or start this project's Metro on a different port and point the app at it.

**What Ceraph does:** Ceraph only reuses a Metro it can confirm is serving this project. If a different project's Metro already holds the port, Ceraph starts this project's Metro on the next free port and points your app at it without a rebuild: an Expo development build is reopened on the new port, a bare React Native app on iOS is launched with the new address, and on Android Ceraph maps the app's port to the new one over ADB. The other project's Metro keeps running untouched.

## "Unable to resolve module"

**What it means:** Metro couldn't find something your code imports, so the bundle fails to build and the app shows the error instead of your screen: *"Unable to resolve module X from Y: X could not be found within the project."* The usual causes are a package that isn't installed, a wrong relative path, a filename whose case doesn't match the import, or a stale Metro cache after you installed, moved, or renamed files.

**Manual fix:** install the missing package, or correct the import path and filename case. If the file and package are definitely there, restart Metro with a clean cache: `npx expo start --clear` or `npx react-native start --reset-cache`.

**What Ceraph does:** this is a code or dependency problem, so reloading doesn't help. `rn_get_errors` returns the module that couldn't be resolved, and your agent fixes the import or installs the package, then drives the app again.

## Code errors go to your agent, not to a reload

Startup and connectivity fixes cannot repair a syntax error or a missing import in application code. Ceraph never reports a clean start over a genuine compile or runtime error, whether it shows as a redbox, as a LogBox error, or is thrown before your first screen mounts. It flags the redbox and puts the error in front of your agent with `rn_get_errors`, which captures:

- Metro bundler errors, including syntax errors and `Unable to resolve module '…'`
- Native build errors
- Uncaught JavaScript exceptions, including ones thrown while your modules load, and unhandled promise rejections
- Network failures and HTTP 5xx responses
- `console.error` calls

The agent reads the real error, fixes the code, and drives the app again in the same conversation.

## Summary

| Error | Cause | Ceraph |
| --- | --- | --- |
| `No script URL provided … unsanitizedScriptURLString = (null)` | App asked for its bundle before Metro was ready | Prevented at bring-up; auto-recovered |
| `Could not connect to development server` | App can't reach Metro | Auto-recovered at iOS startup; re-routed over a USB data cable on an iPhone when the network fails |
| `Unable to load script` (Android) | Device can't reach Metro | Metro route set up over ADB; the app must be running cleanly before "ready" |
| `Disconnected from Metro` / `Reload to reconnect` | Metro restarted, network changed, host slept | Fast Reload reconnects automatically |
| `Cannot find native module`, `TurboModuleRegistry.getEnforcing(...) could not be found` | Installed build predates native changes | Native build inputs fingerprinted; stale builds rebuilt by `ceraph_start` |
| `"main" has not been registered` | Metro running from the wrong folder, or an error while modules loaded | Only this project's Metro is used; the original load-time error is captured and surfaced through `rn_get_errors` |
| Another project's bundle loads | Two Metros on port 8081 | This project's Metro started on a free port; the app is pointed at it automatically |
| `Unable to resolve module` | Missing package, wrong import path, or stale Metro cache | Surfaced to the agent through `rn_get_errors` |
| Syntax errors, exceptions, 5xx | Your code | Surfaced to the agent through `rn_get_errors` |

Run `npx @ceraph/react-native-mcp@latest init` in your project root, then ask your agent to test your app. [Get started here.](/docs/get-started)
