blog / gradle
How to Fix Common Android Gradle Build Errors
Most Android Gradle build errors fall into a handful of families: the Android Gradle plugin (AGP), Gradle and the JDK disagreeing about versions; two dependencies shipping the same class; Java and Kotlin compiling to different bytecode targets; a library needing a higher compileSdk or minSdk; the build running out of memory; and R8 complaining about missing classes in release builds. Below is each error as it appears in the build output, what it actually means and the fix.
Before anything else: scroll to the first error in the Build window, not the last. Gradle prints a cascade of failures, and the root cause is almost always at the top under What went wrong:. Running ./gradlew assembleDebug --stacktrace from a terminal gives you the same output without the IDE’s summarising.
| Error starts with… | Usual cause | Jump to |
|---|---|---|
| Minimum supported Gradle version is… | AGP upgraded, Gradle wrapper not | AGP vs Gradle |
| Android Gradle plugin requires Java 17 | Gradle running on an old JDK | JDK version |
| Inconsistent JVM-target compatibility | Java and Kotlin targets differ | JVM target |
| Cannot add extension with name 'kotlin' | kotlin-android plugin on AGP 9 | Built-in Kotlin |
| Duplicate class … found in modules | Two artifacts contain the same class | Duplicate class |
| Dependency … requires … to compile against version | compileSdk too low | compileSdk/minSdk |
| Namespace not specified | Module missing namespace | Namespace |
| Java heap space / Metaspace / daemon disappeared | Gradle or Kotlin daemon out of memory | Out of memory |
| Missing classes detected while running R8 | Release build references absent code | R8 |
How do I fix “Minimum supported Gradle version is X”?
Minimum supported Gradle version is 9.6.0. Current version is 8.13.
Each AGP release requires a minimum Gradle version. You bumped AGP (often through a version catalog update) and the wrapper still points at the old Gradle. A few recent pairs from the official table:
| AGP | Minimum Gradle |
|---|---|
| 9.5 | 9.6.0 |
| 9.3 | 9.5.0 |
| 9.0 | 9.1.0 |
| 8.13 | 8.13 |
| 8.9 | 8.11.1 |
This table changes with every release, so check the AGP and Gradle compatibility page for your version. Then update the wrapper:
./gradlew wrapper --gradle-version 9.6.0
Run it twice: the first run updates the properties file, the second updates the wrapper scripts and jar. If the build is too broken to run the wrapper task, edit the URL directly:
gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
The reverse problem also exists: Android Studio only supports a range of AGP versions. If Studio says your project’s AGP is unsupported, either upgrade AGP (Studio’s Tools → AGP Upgrade Assistant handles the mechanical changes) or open the project in an older Studio. Upgrade AGP and Gradle in the same commit, and read the release notes for breaking DSL changes before you do.
How do I fix “Android Gradle plugin requires Java 17 to run”?
Android Gradle plugin requires Java 17 to run. You are currently using Java 11.
AGP 8.x and 9.x need at least JDK 17 to run Gradle, and Gradle 9 itself needs Java 17 or newer. The JDK that runs Gradle is not set in your build files; it depends on where you start the build:
- From Android Studio: Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle JDK. The bundled JetBrains Runtime is the safe choice.
- From a terminal or CI:
JAVA_HOME, orjavaon yourPATHif it is unset.
The classic “works in Studio, fails in CI” bug is these two pointing at different JDKs. Set JAVA_HOME to the same JDK Studio uses. Newer Gradle versions can also pin the daemon’s JDK in the repository itself with Daemon JVM criteria, which removes the guesswork for everyone on the team.
The opposite failure is a JDK that is too new for your Gradle version:
Unsupported class file major version 69
Major version 69 is Java 25, 65 is Java 21, 61 is Java 17. Either upgrade Gradle (see the Gradle compatibility matrix) or point Gradle at an older JDK.
What does “Inconsistent JVM-target compatibility” mean?
Inconsistent JVM-target compatibility detected for tasks
'compileDebugJavaWithJavac' (17) and 'compileDebugKotlin' (21).
Java sources are compiled to one bytecode version and Kotlin sources to another. Usually the Java side was set explicitly with compileOptions while the Kotlin side defaulted to the JDK running Gradle. The fix is to make both come from one setting. The cleanest option is a toolchain, which sets both:
app/build.gradle.kts
kotlin {
jvmToolchain(17)
}
Or set them explicitly and identically:
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}
With AGP 9’s built-in Kotlin, Kotlin’s jvmTarget defaults to android.compileOptions.targetCompatibility, so you can usually set only compileOptions and delete the Kotlin line. The old android { kotlinOptions { jvmTarget = "17" } } block is gone under built-in Kotlin; move it to kotlin { compilerOptions { } }. Do not silence the check with kotlin.jvm.target.validation.mode=warning; mismatched targets can produce subtle runtime failures.
Why does AGP 9 say “Cannot add extension with name 'kotlin'”?
Failed to apply plugin 'org.jetbrains.kotlin.android'.
> Cannot add extension with name 'kotlin', as there is an extension
already registered with that name.
AGP 9.0 compiles Kotlin itself and enables this by default, so the org.jetbrains.kotlin.android plugin now conflicts with it. Remove the plugin from every module’s plugins {} block, from the root build file and from your version catalog. Keep the Compose compiler plugin (org.jetbrains.kotlin.plugin.compose) and KSP; only kotlin-android goes.
Two follow-ups often appear right after:
- kapt is incompatible with built-in Kotlin. Migrate to KSP, or as a stopgap replace
kotlin-kaptwithcom.android.legacy-kaptat your AGP version. - kotlinOptions must move to
kotlin { compilerOptions { } }, as above.
If you cannot migrate yet, android.builtInKotlin=false (plus android.newDsl=false) in gradle.properties opts out for now. Google has said that opt-out goes away in AGP 10, so treat it as a temporary bridge. The full steps are in Migrate to built-in Kotlin.
How do I fix “Duplicate class … found in modules”?
Duplicate class com.google.common.util.concurrent.ListenableFuture
found in modules guava-33.0.0-android.jar and listenablefuture-1.0.jar
Two different artifacts on the runtime classpath contain the same fully qualified class. The error names both. Your job is to find who pulls in each one and remove one of them. Start with the dependency tree:
./gradlew :app:dependencies --configuration releaseRuntimeClasspath
./gradlew :app:dependencyInsight --dependency listenablefuture --configuration releaseRuntimeClasspath
Then fix it in this order of preference:
- Upgrade the library that brings in the stale artifact. Duplicate classes usually mean one dependency is years older than the rest.
- Align versions with a BOM. The common Kotlin variant, duplicates between
kotlin-stdlibandkotlin-stdlib-jdk8, exists because those artifacts were merged in Kotlin 1.8. Addingimplementation(platform("org.jetbrains.kotlin:kotlin-bom:2.4.21"))aligns them, but upgrading the old library is better. - Exclude the redundant artifact when you are sure it is a strict subset of the other:
configurations.configureEach {
exclude(group = "com.google.guava", module = "listenablefuture")
}
If the duplicates are android.support.* and androidx.* classes, a library still depends on the pre-2018 Support Library. Replace that library; android.enableJetifier=true rewrites it at build time but slows every build and is a sign of a dependency that is no longer maintained. Fewer, well-maintained libraries avoid most of these conflicts; see essential Android libraries, and keep versions in one place with a Gradle version catalog.
How do I fix compileSdk and minSdk errors from a dependency?
“requires libraries and applications that depend on it to compile against version 36”
Execution failed for task ':app:checkDebugAarMetadata'.
> Dependency 'androidx.core:core-ktx:...' requires libraries and applications
that depend on it to compile against version 36 or later of the Android APIs.
:app is currently compiled against android-35.
A library was built against a newer Android SDK than your compileSdk. The fix is almost always to raise compileSdk:
android {
compileSdk = 36
}
This is safe: compileSdk only controls which APIs you can compile against. It does not change runtime behaviour on devices; targetSdk does that, and you can raise it separately after testing. The catch is that a new API level needs a recent enough AGP: API 36 needs AGP 8.9.1 or later and API 37 needs AGP 9.1.1 or later, per the minimum tools table. The same check can also report that a dependency needs a newer AGP version; the fix is the AGP upgrade above.
If you cannot raise compileSdk yet, pin the dependency to the last version that supported your current one.
“uses-sdk:minSdkVersion 21 cannot be smaller than version 23”
Manifest merger failed : uses-sdk:minSdkVersion 21 cannot be smaller than
version 23 declared in library [com.example:somelib:2.0.0]
A library only runs on newer Android versions than your app supports. Your options, in order: raise your app’s minSdk (check your install base first), use an older version of the library, or add tools:overrideLibrary="com.example.somelib" to <uses-sdk> in your manifest. Only use the last one if you guard every call into that library with an SDK_INT check, because otherwise it crashes on older devices.
How do I fix “Namespace not specified”?
Namespace not specified. Specify a namespace in the module's build file.
Since AGP 8.0 every Android module must declare a namespace in its build file; the package attribute in AndroidManifest.xml is no longer used for this. Add it and remove package from the manifest:
android {
namespace = "com.example.feature.settings"
}
The namespace is the package for the generated R and BuildConfig classes. It does not have to match your applicationId, so changing your published app ID never requires changing it. If the error names a third-party module (common in Flutter and React Native plugins), the fix belongs in that plugin; upgrade it first.
How do I fix Gradle out-of-memory and daemon crashes?
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Metaspace
Gradle build daemon disappeared unexpectedly (it may have been killed or may have crashed)
Gradle’s defaults are modest, and a project with Compose, KSP, several modules and R8 can outgrow them. Raise the limits in the project’s gradle.properties so the change is shared with the team and CI:
gradle.properties
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
kotlin.daemon.jvmargs=-Xmx2g
Setting org.gradle.jvmargs replaces Gradle’s default JVM arguments rather than adding to them, so include the metaspace limit and encoding explicitly. Kotlin compilation runs in its own daemon with its own heap, which is why some OOMs survive a bigger Gradle heap.
“Daemon disappeared” with no stack trace usually means the operating system killed the process for using too much RAM, not that Gradle ran out of heap. On an 8 GB machine or a small CI runner, the fix can be lowering -Xmx and reducing org.gradle.workers.max. Also check how many daemons you have: ./gradlew --status lists them, and ./gradlew --stop kills them. Every distinct Gradle version or JDK spawns its own daemon, so a machine juggling several projects can be running four at once.
How do I fix “Missing classes detected while running R8”?
ERROR: Missing classes detected while running R8. Please add the missing classes
or apply additional keep rules that are generated in
app/build/outputs/mapping/release/missing_rules.txt.
ERROR: R8: Missing class org.conscrypt.Conscrypt (referenced from: ...)
This only appears in builds with optimization enabled, usually release. Some code in your app or a library refers to a class that is not on the classpath. R8 treats that as an error because it cannot tell whether the reference matters.
Open missing_rules.txt and read the class names before pasting anything. There are two cases:
- The class is genuinely needed. You forgot a dependency, or put it in
compileOnly. Add it properly, and the error goes away. - The class is optional. Libraries such as OkHttp reference optional security providers, and annotation-only packages are often absent at runtime. Here a
-dontwarnrule is correct.
-dontwarn org.conscrypt.**
Put the rule in proguard-rules.pro if you use the classic isMinifyEnabled DSL. From AGP 9.3, the new optimization { enable = true } DSL reads keep rules from files ending in .keep under src/main/keepRules/. Either way, also check whether the library has a newer version that ships its own consumer rules; that is the cleanest fix.
Never paste a blanket -dontwarn ** or -keep class ** { *; } to make R8 quiet. The first hides real crashes until a user hits them; the second throws away most of what R8 does for app size. Our guide to reducing Android app size covers writing narrow keep rules.
What should I try when none of these match?
- Read the first error, with
--stacktrace. Add--infoif you need to see which task and input caused it. - Check what you changed last.
git diffonlibs.versions.toml,gradle-wrapper.propertiesandgradle.propertiesexplains most new failures. - Clear caches only after reading the error.
./gradlew cleanand File → Invalidate Caches fix corrupted outputs, but they will not fix a version mismatch, and they cost you a full rebuild. - Use a Build Scan.
./gradlew assembleDebug --scanuploads a report with the full dependency graph and task timeline. Do not run it on a private project without checking your company’s policy, since the report is hosted externally.
Most build breakages come from upgrades, so the best prevention is upgrading one thing at a time: AGP with its matching Gradle, then Kotlin, then libraries, with a green build between each step.
Frequently asked questions
Why does my build work in Android Studio but fail on the command line?
They are usually running Gradle on different JDKs. Studio uses the Gradle JDK from its settings, while a terminal uses JAVA_HOME or the java on your PATH. Point both at the same JDK, or pin it for the project with Gradle's Daemon JVM criteria.
Does Invalidate Caches / Restart fix Gradle build errors?
Only errors caused by corrupted IDE indexes or build outputs. It does nothing for version mismatches, duplicate classes or missing dependencies, which make up most build failures, so read the first error before reaching for it.
Is it safe to raise compileSdk to fix a dependency error?
Generally yes. compileSdk only decides which Android APIs you can compile against and does not change how the app behaves on devices. targetSdk is the setting that opts you into new platform behaviour, and you can raise it separately after testing. A newer compileSdk may require a newer AGP.
Which JDK version do I need for Android builds?
AGP 8.x and 9.x need at least JDK 17 to run, and the JetBrains Runtime bundled with Android Studio meets that. Check the compatibility table in the AGP release notes when you upgrade, because the minimum can rise.
Should I add the rules from missing_rules.txt to fix R8 errors?
Read them first. If a missing class is something your app needs, add the dependency instead. If it is an optional class a library references, such as an alternative security provider, a narrow -dontwarn rule for that package is the correct fix.