如何修復 React Native 建置錯誤:從 Gradle、Xcode 和 Metro 日誌找出真正原因
How to fix React Native build errors: Find the real error in Gradle, Xcode and metro logs
指南展示如何排查 React Native 建置錯誤,重點是從 Gradle、Xcode、CocoaPods、Metro 或裝置日誌較早出現的具體錯誤找出原因,而非依賴最後的 BUILD FAILED 訊息。
When a React Native build fails, the last line of the log ("BUILD FAILED", or a red screen on the device) almost never tells you the cause. The real error is somewhere above it, in Gradle, Xcode, CocoaPods, Metro or the device log.
This guide covers how to find it fast, with fixes for six errors React Native developers run into all the time. For each one I'll show the raw error and what rn-build-doctor, a free, open-source CLI I built, reports for it. All the output below is real, from React Native 0.86 and 0.87 apps, an Expo SDK 57 project, Xcode 26 and an Android 14 emulator.
RN Build Doctor
Evidence-based diagnostics for React Native and Expo build, release, and startup failures.
rn-build-doctor reads your project and the logs you give it, runs deterministic checks, and tells you:
-
What failed: the primary error, not the final
BUILD FAILEDline. - What evidence supports it: log excerpts with original line numbers, and the project files and versions involved.
- What to check next: specific steps, with a way to verify the fix.
- How to share it safely: a redacted Markdown or JSON report you can review before posting.
It never guesses silently. When a log doesn't match a supported pattern, it says "No supported diagnosis" and shows the first error lines instead of inventing a cause. AI is optional, opt-in, and shown separately from verified findings.
Status: 0.1 preview. The rule catalog is narrow on purpose: 40 rules, each with fixtures and a cited source. See supported checks and known…
Quick start
You don't need to install anything. Run these from your project root (the folder with package.json), with Node.js 22.12 or later:
# Android build fails
(cd android && ./gradlew assembleDebug) 2>&1 | npx rn-build-doctor analyze -
# iOS build fails
xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -sdk iphonesimulator build 2>&1 | npx rn-build-doctor analyze -
# pod install fails
(cd ios && pod install) 2>&1 | npx rn-build-doctor analyze -
# JavaScript bundling fails
npx expo export 2>&1 | npx rn-build-doctor analyze -
# App crashes or shows a red screen on Android
adb logcat -d | npx rn-build-doctor analyze -
# Check the project before building
npx rn-build-doctor scan
Two details that matter:
- Add 2>&1 so errors printed to stderr are included.
- Keep the tool running from the project root (that's why the Gradle command is in parentheses). It reads package.json, node_modules, gradle.properties and your Android/iOS config to tell apart causes that produce the same error text.
Every finding shows what failed, the log lines that prove it (with line numbers), next steps, and how to verify the fix.
Why the last line lies
Here is the bottom of a real failed Gradle build:
Everything you see first is generic: "Run with --stacktrace", deprecation notices, BUILD FAILED. The useful part is the "What went wrong" section further up, and in bigger builds it can be hundreds of lines above. Rule one of debugging React Native builds: search for the earliest specific error, not the last line.
1. Manifest merger failed: uses-sdk:minSdkVersion 24 cannot be smaller than version 26
The raw error:
Execution failed for task ':app:processDebugMainManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 24 cannot be smaller than version 26 declared in library [androidx.health.connect:connect-client:1.1.0]
What it means: a library you added (directly or through a React Native package) only supports Android 8.0 (API 26) and up, but your app says it supports API 24. Gradle refuses to build an app that would install on devices the library doesn't support.
What rn-build-doctor reports:
The fix, in order of preference:
- Raise minSdkVersion to 26 in android/build.gradle (the minSdkVersion value in buildscript.ext). In Expo, set android.minSdkVersion with expo-build-properties.
- Or use a version of the library (or of the React Native package that pulls it in) that supports your minSdk. Run cd android && ./gradlew :app:dependencies to see who requires it.
- Only use tools:overrideLibrary if every call into the library checks the API level at runtime. Otherwise the app crashes on older devices.
2. Unable to load script. Make sure you're running Metro (red screen)
The raw message (from adb logcat):
W unknown:BridgelessReact: ReactHost{0}.handleHostException(message = "Unable to load script.
Make sure you're running Metro or that your bundle 'index.android.bundle' is packaged correctly for release.
What it means: a debug build loads its JavaScript from the Metro dev server, and the app couldn't reach it. With the New Architecture (the default since React Native 0.76), this doesn't crash the app. You get a red screen and only a warning in logcat, which makes it easy to miss if you're searching the log for crashes.
What rn-build-doctor reports:
The fix:
npx react-native start # or: npx expo start
adb reverse tcp:8081 tcp:8081 # for a USB-connected Android device
On Wi-Fi, set the dev server address in the dev menu to your computer's IP and port 8081. If this happens in a release build, the bundle wasn't packaged: check that the createBundleReleaseJsAndAssets task ran.
3. Signing for "MyApp" requires a development team
The raw error (xcodebuild):
error: Signing for "MyApp" requires a development team. Select a development team in the Signing & Capabilities editor.
What it means: you're building for a real device (or archiving), and the iOS target has no DEVELOPMENT_TEAM set, so Xcode can't sign the app.
What rn-build-doctor reports:
The fix: in Xcode, select the target → Signing & Capabilities → choose a team. In CI, pass DEVELOPMENT_TEAM=YOURTEAMID to xcodebuild. With Expo/EAS, let EAS manage credentials (eas credentials) or set ios.appleTeamId.
4. Unrecognized VM option 'MaxPermSize=512m'
The raw error:
Unable to start the daemon process.
Unrecognized VM option 'MaxPermSize=512m'
Error: Could not create the Java Virtual Machine.
What it means: your android/gradle.properties still has -XX:MaxPermSize in org.gradle.jvmargs, a leftover from old React Native templates. JDK 8 removed the permanent generation, and newer JDKs refuse to start with that option, so Gradle can't even launch. You'll usually hit this when an older project meets a newer JDK.
What rn-build-doctor reports (when run from the project, it also points to the exact gradle.properties line):
The fix: remove -XX:MaxPermSize=512m from org.gradle.jvmargs (use -XX:MaxMetaspaceSize if you need a limit), then run cd android && ./gradlew --stop so no old daemon is reused.
5. Android Gradle plugin requires Java 17 to run. You are currently using Java 11
What it means: Android Gradle Plugin 8 and later need JDK 17, and Gradle picked up an older JDK.
rn-build-doctor's output:
ERROR F1 Gradle is running on Java 11, but the Android Gradle Plugin requires Java 17
android.agp-requires-newer-jdk · confidence high · android
Next steps:
1. Install JDK 17. For example, the React Native docs recommend Azul Zulu 17.
2. Point JAVA_HOME at the JDK 17 installation, or set org.gradle.java.home in android/gradle.properties.
3. If the build runs inside Android Studio, set Settings > Build, Execution, Deployment > Build Tools > Gradle > Gradle JDK.
4. Stop old daemons with `cd android && ./gradlew --stop`.
Gradle uses the JDK from org.gradle.java.home first, then JAVA_HOME, then the java on your PATH, and Android Studio has its own Gradle JDK setting. That's why it can work in Android Studio and fail in the terminal (or the other way round). npx rn-build-doctor scan shows which JDK your shell is using before you build.
6. Unable to resolve module X from App.tsx (Metro)
The raw error:
error Unable to resolve module lottie-react-native from /Users/dev/MyApp/App.tsx: lottie-react-native could not be found within the project or in these directories:
node_modules
The same error text has different causes: the package isn't installed, it's installed but not in package.json, Metro's cache is stale, a path alias isn't configured, or a relative import has the wrong letter case (which works on macOS but fails on Linux CI and EAS). Because rn-build-doctor reads package.json and node_modules, it tells them apart:
ERROR F1 Unable to resolve 'lottie-react-native' from App.tsx
javascript.unable-to-resolve-module · confidence high · javascript
Package 'lottie-react-native' is imported but isn't declared in package.json and isn't installed.
Next steps:
1. Install it with your package manager (for example `npm install lottie-react-native`).
Bonus: Kotlin compile errors after an upgrade
Native compile errors are easy to lose in Gradle output. rn-build-doctor pulls out the file, line and column, and if the file is inside node_modules, it tells you which npm package it belongs to (usually a library that doesn't support your React Native version yet):
ERROR F1 Kotlin compile error in MainApplication.kt:28:24: Unresolved reference 'PackageList'.
The Kotlin compiler reported 2 errors, so :app:compileDebugKotlin failed.
Use it in CI (GitHub Actions)
- run: |
set -o pipefail # without it, the step takes tee's exit code and never fails
npx expo export --platform android 2>&1 | tee build.log
- if: failure()
run: npx rn-build-doctor analyze build.log && npx rn-build-doctor report --output "$GITHUB_STEP_SUMMARY"
The diagnosis appears in the job summary. Add --fail-on error to scan or analyze to fail a pipeline on findings.
Share a build failure safely
npx rn-build-doctor report --output build-report.md
This creates a Markdown report you can attach to a GitHub issue or paste into Slack. It's redacted (tokens, keys, passwords, auth headers, your home directory), and .env values are never read. scan and analyze run fully offline, and the test suite fails if they open a network connection. Redaction is best-effort, so give the report a quick read before sharing.
When it doesn't know the error
It has 40 checks today. If your failure isn't one of them, it says "No supported diagnosis" and shows the first error lines instead of guessing. There's also an optional, opt-in AI explanation (npx rn-build-doctor explain --dry-run shows exactly what would be sent first).
If you hit a failure it doesn't recognize, please open an issue with the anonymized log. Real logs are how new checks get added.
FAQ
Does it work with Expo?
Yes. It understands Expo CLI output, EAS build logs, app config, config plugins, SDK version mismatches and EXPO_PUBLIC_ environment variables.
Does it send my logs anywhere?
No. scan, analyze and report never make network requests. Only the optional explain command contacts an AI provider, after showing you what it will send and asking for confirmation.
Do I need to install it?
No. npx rn-build-doctor runs the latest version. You can also add it as a dev dependency: npm install --save-dev rn-build-doctor.
Does it fix my project automatically?
No, on purpose. It only reads files and recommends changes, so you stay in control of your project.
If this helped, a ⭐ on GitHub helps other React Native developers find it.
來源:DEV Community · dev.to





