Skip to main content

The 10 Most Common Expo Errors and How to Fix Them

Updated 7 min readMarkdown
Part of seriesShipping Expo Apps to Production

Most Expo errors fall into one of four layers: Metro couldn't bundle your code, JavaScript crashed at runtime, a native module is missing from the binary you're running, or the native build (Xcode or Gradle) failed. Naming the layer first is half the fix.

Here are the ten errors that come up most, what they mean and how to fix them. If yours isn't here, paste it into the free React Native & Expo Error Fixer and it will explain the cause and the fix.

Before anything else, two commands fix a surprising number of problems:

npx expo start --clear     # restart Metro with an empty cache
npx expo-doctor            # check your project for known issues

1. Unable to resolve module

Unable to resolve module ./components/Header from App.tsx:
./components/Header could not be found within the project

Layer: Metro.

Why: the import path doesn't match a real file, the package isn't installed, or Metro is serving a stale cache after you moved or renamed something. A common one: the file is header.tsx but you import ./Header. macOS ignores case, but Linux CI and EAS Build don't.

Fix:

  • Check the path and the exact capitalisation.
  • For a package, install it with npx expo install <package> so you get the version that matches your SDK.
  • Restart with npx expo start --clear.
  • If you use path aliases like @/components, make sure they're set in tsconfig.json (Expo reads paths from it).

Paste your resolve error into the Error Fixer →

2. "main" has not been registered

Invariant Violation: "main" has not been registered.

Layer: JavaScript, at startup.

Why: the app's entry file never ran registerRootComponent, usually because something crashed while the first modules were loading, or Metro is running from the wrong folder (common in monorepos).

Fix:

  • Scroll up: the real error is usually printed just above this one. Fix that first.
  • Run npx expo start from the app's own folder.
  • If you changed the entry point, check the main field in package.json (expo-router/entry for Expo Router, or a file that calls registerRootComponent(App)).

3. Text strings must be rendered within a <Text> component

Error: Text strings must be rendered within a <Text> component.

Layer: JavaScript, at render.

Why: a raw string or number is sitting directly inside a View. The sneaky version is a conditional: {count && <Badge />} renders the number 0 when count is 0.

Fix:

  • Wrap text in <Text>.
  • Make conditionals return a boolean: {count > 0 && <Badge />} or {!!count && <Badge />}.
  • Look for stray characters, like a space or ; left between JSX tags.

4. VirtualizedLists should never be nested inside plain ScrollViews

VirtualizedLists should never be nested inside plain ScrollViews
with the same orientation because it can break windowing and other functionality

Layer: JavaScript (a warning, but a real performance problem).

Why: a FlatList inside a vertical ScrollView renders every row at once, so you lose the virtualization that makes lists fast.

Fix: remove the outer ScrollView and move the content above and below the list into ListHeaderComponent and ListFooterComponent. If you need several lists on one screen, use a SectionList.

5. Native module not found in Expo Go

Error: Cannot find native module 'ExpoSomething'
Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'RNSomething' could not be found.

Layer: native module.

Why: Expo Go only contains the native code for the libraries bundled into it. A library with its own native code that isn't one of them will install fine and then crash at runtime.

Fix: create a development build, which is your own version of Expo Go with your libraries compiled in:

npx expo install expo-dev-client
eas build --profile development --platform ios   # or android

If you're already on a development build and see this, you added the library after building. Rebuild.

6. Element type is invalid

Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined.

Layer: JavaScript.

Why: an import resolved to undefined. Almost always a default/named import mix-up: import Header from './Header' when the file does export function Header, or the other way around. Circular imports can cause it too.

Fix: match the import to the export (import { Header } from './Header' for a named export). The error's component stack tells you which component was undefined.

7. Too many re-renders

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

Layer: JavaScript.

Why: state is set during render. The classic: onPress={setOpen(true)} calls the function immediately instead of passing it.

Fix:

  • Pass a function: onPress={() => setOpen(true)}.
  • Move state updates that depend on props into an event handler or a useEffect with the right dependencies.
  • The related "Maximum update depth exceeded" usually means a useEffect updates a value that's in its own dependency list.

8. Network request failed

TypeError: Network request failed

Layer: JavaScript, but the cause is usually the network setup.

Why: on a phone, localhost is the phone, not your computer. Other causes: plain http:// URLs, which Android blocks by default (and iOS App Transport Security restricts), or a server that isn't reachable from the device's network.

Fix:

  • Use your computer's LAN IP (for example http://192.168.1.20:3000) or a tunnel, and keep the phone on the same Wi-Fi.
  • Use https for anything outside local development.
  • Read the URL from an environment variable (EXPO_PUBLIC_API_URL) so dev and production can differ.

9. Package versions don't match your Expo SDK

The following packages should be updated for best compatibility with the installed expo version:
  react-native-reanimated@3.x.x - expected version: ~3.y.y

Layer: everywhere. Mismatched versions cause crashes at runtime and failures at build time.

Why: a library was installed with npm install instead of npx expo install, or the SDK was upgraded without updating its packages.

Fix:

npx expo install --fix
npx expo-doctor

When upgrading the SDK, follow the release notes and run npx expo install expo@^<version> --fix.

10. EAS Build failed

Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information.

or on iOS, a failed "Install pods" or "Run fastlane" phase.

Layer: native build.

Why: the last line rarely says much. The real cause is further up in the phase that failed: often a version mismatch (see #9), a config plugin that needs a setting you haven't added, or credentials and signing.

Fix:

  • Open the failed phase in the EAS build page and search for the first error: line.
  • Run npx expo-doctor and fix what it reports.
  • Reproduce locally with npx expo prebuild --clean and then npx expo run:android or npx expo run:ios, which is much faster to iterate on than cloud builds.

Paste the failed build log into the Error Fixer →

A debugging routine that works for most of these

  1. Read the first error, not the last line. Red screens and build logs often end with something generic.
  2. Name the layer: Metro, JavaScript, native module or native build.
  3. Check how you run the app. Expo Go, a development build and a bare project behave differently.
  4. Clear caches with npx expo start --clear before deeper changes.
  5. Align versions with npx expo install --fix.

If you're stuck on an error that isn't in this list, the free React Native & Expo Error Fixer explains it in plain English: paste the error, choose where it happens and how you run the app, and it gives you the likely causes and the fix. It's made by RapidNative, where I work.

What's the Expo error that has cost you the most time? Drop it in the comments.

No comments yet. Be the first to comment.

Shipping Expo Apps to Production

Part 4 of 4

Practical, production-focused guides for React Native and Expo developers: OTA updates, EAS builds, push notifications, auth and payments. What to set up, what breaks, and how to ship with confidence.

Start from the beginningExpo Push Notifications: Your First Push, and Why It Didn't ArriveDevelopment builds, FCM and APNs credentials, push tokens, test sends and the fixes for missing notifications