LEARN · DEBUGGING GUIDE

Debugging React Native Android Gradle Build Failures

Gradle build errors in React Native Android often stem from cache corruption, version mismatches, or missing SDK components. Here's how to fix them without nuking your project.

IntermediateMobile8 min read

What this usually means

React Native Android builds rely on a fragile chain of Gradle configurations, local caches, and SDK versions. The most common class of errors comes from version mismatches—between your React Native version, the Android Gradle Plugin (AGP), Kotlin, or the NDK. Another frequent culprit is a corrupted Gradle cache (especially the `.gradle` folder or Android Studio's caches), which leads to resolution failures for dependencies. Less obvious but equally painful: missing or misconfigured `local.properties` (especially the SDK path), or a Maven repository that's dropped from Gradle files after an upgrade. These symptoms often surface after switching branches, updating packages, or moving the project between machines.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run `npx react-native doctor` to check for environment issues (Node, Java, Android SDK, NDK).
  • 2Check `android/build.gradle` and `android/app/build.gradle` for the AGP version (`classpath 'com.android.tools.build:gradle:X.X.X'`) and ensure it matches React Native's requirements.
  • 3Run `cd android && ./gradlew clean` then `./gradlew assembleDebug --stacktrace` and inspect the first error in the stacktrace.
  • 4Open `~/.gradle/gradle.properties` (or project-level `gradle.properties`) and check `org.gradle.jvmargs`—if it's too low, increase to `-Xmx2048m` or higher.
  • 5Verify `android/local.properties` exists and points to the correct SDK path (e.g., `sdk.dir=/Users/you/Library/Android/sdk`).
( 02 )Where to look

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

  • search`android/build.gradle` — the top-level build file with repository and dependency declarations.
  • search`android/app/build.gradle` — module-level build config, including `compileSdkVersion`, `targetSdkVersion`, and React Native overrides.
  • search`android/gradle/wrapper/gradle-wrapper.properties` — the Gradle distribution version.
  • search`~/.gradle/caches/` — the global Gradle cache; often corrupted after incomplete downloads.
  • search`android/.gradle/` — the project-level Gradle cache; delete it to force a clean resolution.
  • searchAndroid Studio's 'Build Output' pane and the 'Messages' tab for detailed error logs.
  • search`node_modules/react-native/ReactAndroid/gradle.properties` — the React Native module's build config.
( 03 )Common root causes

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

  • warningCorrupted Gradle cache: partially downloaded artifacts or stale metadata cause resolution failures.
  • warningAGP version incompatibility: React Native requires a specific AGP range (e.g., 7.x for RN 0.71+).
  • warningJDK version mismatch: React Native 0.71+ needs JDK 11 or 17; JDK 8 or 18+ causes 'Unsupported class file major version'.
  • warningMissing or outdated NDK: React Native's Hermes engine requires NDK r21e or later.
  • warningDependency version conflict: multiple versions of the same library (e.g., `androidx.core:core`) from different packages.
  • warningMaven repository order: if a required repo (e.g., `jitpack.io` for some native modules) is missing or ordered after `google()` and `mavenCentral()`, resolution fails.
( 04 )Fix patterns

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

  • buildWipe all caches: `cd android && ./gradlew clean && rm -rf ~/.gradle/caches/ && rm -rf .gradle/` then rebuild.
  • buildPin exact versions in `app/build.gradle` for conflicting dependencies using `force` or `exclude` blocks.
  • buildUpdate `gradle-wrapper.properties` to the recommended Gradle version for your AGP (e.g., Gradle 7.5 for AGP 7.4).
  • buildSet `org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m` in `gradle.properties` to avoid GC overhead errors.
  • buildAdd missing Maven repositories (e.g., `maven { url 'https://jitpack.io' }`) at the top of the `allprojects` block in `android/build.gradle`.
  • buildInstall or update the NDK via SDK Manager (SDK Tools tab) and set `ndk.dir` in `local.properties` if needed.
( 05 )How to verify

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

  • verifiedRun `cd android && ./gradlew assembleDebug --daemon` and confirm it completes with BUILD SUCCESSFUL.
  • verifiedRun `npx react-native run-android` and verify the app installs and launches on your emulator or device.
  • verifiedCheck `adb logcat | grep ReactNativeJS` for any runtime crashes after build.
  • verifiedRun `npx react-native doctor` again to ensure no new issues were introduced.
  • verifiedPerform a clean build on a CI-like environment (e.g., `./gradlew clean assembleDebug --no-daemon`) to ensure cache independence.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDeleting `node_modules` and `yarn.lock` before verifying the Gradle cache is the problem—loss of lock file can introduce version changes.
  • warningBlindly upgrading AGP or Gradle wrapper without checking React Native compatibility—often breaks more than it fixes.
  • warningIgnoring the first error in the stacktrace—Gradle output can be verbose, but the root cause is usually at the top.
  • warningRunning `./gradlew clean` without clearing the Gradle cache—clean only removes build outputs, not cached artifacts.
  • warningEditing `build.gradle` files without backing them up—a single syntax error can break the entire build for all developers.
  • warningAssuming the error is in your own code—most Gradle errors are environment or dependency related.
( 07 )War story

The Mystery of the Missing Hermes Bytecode

Mobile EngineerReact Native 0.72, Android Gradle Plugin 8.1, Gradle 8.3, JDK 17, Hermes enabled

Timeline

  1. 09:15Pulled latest master branch; ran `npx react-native run-android`.
  2. 09:17Build failed with 'Execution failed for task ':app:mergeExtDexDebug'.' and a long stacktrace about 'java.lang.OutOfMemoryError: GC overhead limit exceeded'.
  3. 09:20Checked `gradle.properties`; `org.gradle.jvmargs` was set to `-Xmx1024m`. Increased to `-Xmx2048m`.
  4. 09:25Rebuild; still failed, but now with 'Could not resolve com.facebook.react:react-native:0.72.0'.
  5. 09:30Cleared Gradle cache (`rm -rf ~/.gradle/caches/`) and project `.gradle` folder.
  6. 09:32Rebuild; new error: 'No compatible version of the Android NDK is available. Required NDK version is r21e.'
  7. 09:35Opened SDK Manager; found NDK r23c installed, but no r21e. Installed NDK r21e via SDK Tools.
  8. 09:40Set `ndk.dir` in `local.properties` to point to the newly installed NDK.
  9. 09:42Rebuild; success! App launched on emulator.

I had just merged a colleague's branch that upgraded React Native from 0.71 to 0.72. The build immediately failed with a GC overhead error—common when Gradle runs out of memory during dex merging. I bumped the JVM heap to 2GB, but that only revealed a second error: 'Could not resolve react-native:0.72.0'. That was weird because the dependency was declared in `app/build.gradle` and the Maven repos were correct.

I decided to nuke the Gradle caches—both global and project-level. After a lengthy rebuild, the error changed again: 'No compatible version of the Android NDK is available'. React Native 0.72 requires NDK r21e for Hermes, but our team had NDK r23c installed. The mismatch was silently causing the resolution failure earlier because Gradle couldn't find the right NDK to satisfy the Hermes native build.

I installed NDK r21e via the SDK Manager, updated `local.properties` to point to the correct path, and ran the build again. This time it succeeded. The lesson: when upgrading React Native major versions, always check the NDK requirement. Also, clearing caches step-by-step reveals hidden dependencies—never assume the first error is the real problem.

Root cause

Missing NDK r21e required by React Native 0.72's Hermes engine, combined with insufficient JVM heap for dex merging.

The fix

Installed NDK r21e via Android SDK Manager, updated `local.properties` with `ndk.dir`, and increased `org.gradle.jvmargs` to `-Xmx2048m`.

The lesson

When upgrading React Native, always check `react-native.config.js` and the React Native GitHub release notes for NDK requirements. Never clear all caches at once—do it incrementally to isolate the real cause.

( 08 )Understanding the Gradle Dependency Resolution Chain

Gradle resolves dependencies by checking repositories in the order defined in `repositories` blocks. For React Native, the default order is `google()`, `mavenCentral()`, and `maven { url 'https://www.jitpack.io' }`. If a dependency is not found in the first repository, it tries the next. A common issue is when a native module (e.g., react-native-image-picker) requires a library only available on JitPack, but JitPack is listed after `google()` and `mavenCentral()`. If those repositories have a stale version or a different artifact, Gradle may resolve the wrong one or fail entirely.

To inspect the resolution, run `./gradlew :app:dependencies --configuration debugRuntimeClasspath`. This outputs the full dependency tree, including version conflicts. Look for lines with 'FAILED' or '(*)'. Use `force` or `exclude` in `app/build.gradle` to pin specific versions: `configurations.all { resolutionStrategy { force 'androidx.core:core:1.9.0' } }`.

( 09 )The Hidden Impact of Incremental Builds and Daemon Caching

Gradle uses a build daemon that caches classloaders and project metadata. While this speeds up builds, it can cause stale state. If you change JDK versions or install new SDK components without restarting the daemon, you'll see confusing errors like 'Unsupported class file major version' or 'Failed to load native library'. Always run `./gradlew --stop` to kill the daemon after environment changes.

Similarly, Android Studio's build cache (`~/.android/build-cache`) can hold corrupted intermediate files. If you're seeing dex merge errors that don't make sense, delete this folder: `rm -rf ~/.android/build-cache`. On Windows, it's `%USERPROFILE%\.android\build-cache`. This is a nuclear option that often fixes 'mergeExtDex' failures.

( 10 )Decoding the Stacktrace: First Error vs. Root Cause

When Gradle fails, it outputs a stacktrace that can be hundreds of lines. The first line that says 'What went wrong:' is the surface error. But the real cause is often a few lines earlier in the 'Caused by:' chain. For example, 'Could not resolve com.facebook.react:react-native:0.72.0' might be followed by 'Caused by: org.gradle.api.resources.ResourceException: Could not get resource' and then 'Caused by: java.io.IOException: No space left on device'. The root cause is disk space, not a missing dependency.

Train yourself to read the stacktrace from the bottom up. Look for the first 'Caused by:' that is a real system error (I/O, OOM, missing file) rather than a Gradle resolution exception. That's where to focus your debugging efforts.

( 11 )Hermes vs. JSC: Build Configuration Pitfalls

React Native 0.71+ defaults to Hermes. If you enable Hermes, your build requires the NDK to compile Hermes bytecode. The `app/build.gradle` includes `def enableHermes = true`. A mismatch between the NDK version and what Hermes expects can cause silent failures. Check `node_modules/react-native/ReactAndroid/gradle.properties` for `hermesVersion` and ensure your NDK matches the one specified (usually r21e).

If you disable Hermes (`enableHermes = false`), the build uses JSC (JavaScript Core). JSC is bundled as a prebuilt library, so NDK is not needed. However, JSC has its own versioning issues—ensure your `react-native` version ships a compatible JSC. You can verify by checking `node_modules/jsc-android/package.json` for the version.

( 12 )Automated Diagnostics: Beyond react-native doctor

`npx react-native doctor` is a good first step, but it doesn't catch all Gradle-specific issues. For a deeper check, create a script that runs `./gradlew projects` and `./gradlew :app:properties`. The first command verifies the project structure; the second outputs all build properties including `android.compileSdkVersion`, `android.minSdkVersion`, and `android.targetSdkVersion`. Compare these with React Native's recommended values (e.g., compileSdk 34 for RN 0.73).

Another useful tool is `./gradlew buildEnvironment` which shows the Android Gradle Plugin version and its dependencies. A mismatch between AGP and Gradle wrapper versions is a frequent cause of 'Unable to find a matching configuration' errors. Use the official compatibility table: https://developer.android.com/build/releases/gradle-plugin#compatibility

Frequently asked questions

Why does clearing the Gradle cache fix the build but 'clean' alone doesn't?

`./gradlew clean` only removes the `build/` directories (compiled outputs), not the cached artifacts in `~/.gradle/caches/` or `android/.gradle/`. The cache stores downloaded dependencies and metadata. If a dependency download was interrupted or corrupted, the cache holds a broken artifact. Clearing the cache forces Gradle to redownload everything fresh. However, avoid clearing the global cache unnecessarily—it's shared across projects and clearing it will slow down all builds until the cache is repopulated.

I'm getting 'Unsupported class file major version'—what does it mean?

This error indicates that a Java class file was compiled with a newer JDK version than the one Gradle is using. For example, if you compile a native module with JDK 17 but your Gradle process runs on JDK 11, you'll see this error. The fix is to ensure your `JAVA_HOME` points to a JDK that matches the one used by Gradle (set in `gradle.properties` via `org.gradle.java.home`). React Native 0.71+ supports JDK 11 and 17. If you're using JDK 18+, downgrade to JDK 17.

How do I fix 'Project with path ':react-native-some-module' could not be found'?

This usually happens when a native module is linked but its `android/build.gradle` file is missing or misconfigured. First, verify the module is installed: `ls node_modules/react-native-some-module/android`. If the folder exists, check `settings.gradle` in `android/` for the line `include ':react-native-some-module'`. If not, add it manually. Also ensure `app/build.gradle` has `implementation project(':react-native-some-module')`. For auto-linking (RN 0.60+), run `npx react-native link` (deprecated) or reinstall the module.

What should I do if I see 'GC overhead limit exceeded' during build?

This means Gradle ran out of memory during the build. Increase the JVM heap size in `android/gradle.properties`: set `org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m`. If the error persists, increase to `-Xmx4096m`. Also, enable the Gradle daemon (`org.gradle.daemon=true`) to reuse JVM instances. If you're running on a CI machine with limited memory, consider reducing the number of parallel tasks: `org.gradle.parallel=false`.

After updating React Native, the build fails with 'Conflict with dependency'. How do I resolve it?

Dependency conflicts arise when two libraries request different versions of the same transitive dependency. Run `./gradlew :app:dependencies` to see the conflict. In `app/build.gradle`, use `resolutionStrategy` to force a version: `configurations.all { resolutionStrategy { force 'com.google.android.gms:play-services-auth:20.5.0' } }`. Alternatively, use `exclude` to remove a conflicting transitive dependency: `implementation('com.example:library:1.0') { exclude group: 'com.android.support' }`.