
Introduction
If you have been building Android apps for some time, you have almost certainly hit a wall with this error during a Gradle build:
Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in
kotlin-stdlib-1.8.x (org.jetbrains.kotlin:kotlin-stdlib:1.8.x)
kotlin-stdlib-jdk8-1.8.x (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.x)
Or perhaps something like:
Duplicate class android.support.v4.app.Fragment found in modules
jetified-support-fragment-1.0.0 and fragment-1.x.x
Build fails. The app won’t compile. You stare at the terminal wondering what went wrong especially since everything was fine yesterday.
This guide walks you through every major cause of the “Duplicate class found” error in Android, and gives you copy-paste-ready fixes for each scenario. Whether you are a solo indie developer or part of a large team, these solutions will get your build green again.
Problem Statement
The Duplicate class found error is a compile-time classpath conflict. It occurs when two or more dependencies on your Gradle classpath provide the same fully-qualified Java/Kotlin class name.
Android’s build toolchain (D8 / R8) cannot decide which copy of the class to include in the final DEX output, so it fails fast with this error rather than silently picking one.
When does this typically appear?
Note: This error only surfaces at build time — it never reaches users. But it is a hard blocker that stops every developer on your team until fixed.
Root Causes
Before jumping to fixes, understanding the root causes helps you pick the right solution:
- Support Library + AndroidX Co-existence
Google replaced the old com.android.support library with androidx.* starting in AndroidX 1.0 (2018). Including both in the same project causes class conflicts because many classes were renamed (but not deleted from the old library).
- Kotlin Stdlib Splitting (Kotlin 1.8+)
Before Kotlin 1.8.0, kotlin-stdlib-jdk7 and kotlin-stdlib-jdk8 were separate artifacts. From Kotlin 1.8.0 onwards, their content was merged into kotlin-stdlib. If your project or any dependency explicitly declares kotlin-stdlib-jdk7 or kotlin-stdlib-jdk8, Gradle pulls in the old artifacts alongside the new merged kotlin-stdlib, causing duplicates.
- Transitive Dependency Conflicts
When Library A depends on okhttp:3.x and Library B depends on okhttp:4.x, Gradle may resolve both on the classpath. These contain overlapping classes.
- Duplicate Declarations Across Modules
In multi-module Android projects, the same dependency can be declared in multiple modules at different versions, leading to conflicts when the final APK/AAB is assembled.
Solution & Implementation
Work through the fixes below in order. Most projects are resolved by Fix 1 or Fix 2.
Fix 1: Enable AndroidX and Jetifier
Applicable when: You are mixing com.android.support and androidx.* libraries.
Open your gradle.properties file (project root) and add:
# gradle.properties
# Enables AndroidX artifact mapping
android.useAndroidX=true
# Automatically converts Support Library dependencies to AndroidX equivalents
android.enableJetifier=true
Then perform a full Gradle sync and rebuild.
What Jetifier does: It rewrites bytecode of legacy com.android.supportdependencies on-the-fly to use androidx.* namespaces, eliminating the class duplication.
Verification: After enabling Jetifier, run:
./gradlew :app:dependencies | grep "support"
You should see no raw com.android.support entries remaining (they will all appear as justified* versions).
Fix 2: Exclude Duplicate Kotlin Stdlib Classes
kotlin-stdlib-1.8.x and kotlin-stdlib-jdk8-1.8.x
Applicable when: You see errors like:
Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules
Open your app-level build.gradle (or build.gradle.kts) and add a resolution strategy:
Groovy DSL (build.gradle):
// app/build.gradle
dependencies {
// ... your existing dependencies
// Force Kotlin stdlib consolidation (Kotlin 1.8+ merged jdk7/jdk8 into stdlib)
constraints {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7") {
version {
require "1.8.0"
}
because "kotlin-stdlib-jdk7 is merged into kotlin-stdlib since 1.8.0"
}
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") {
version {
require "1.8.0"
}
because "kotlin-stdlib-jdk8 is merged into kotlin-stdlib since 1.8.0"
}
}
}
Kotlin DSL (build.gradle.kts):
// app/build.gradle.kts
dependencies {
// ... your existing dependencies
constraints {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7") {
version { require("1.8.0") }
because("kotlin-stdlib-jdk7 is merged into kotlin-stdlib since 1.8.0")
}
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") {
version { require("1.8.0") }
because("kotlin-stdlib-jdk8 is merged into kotlin-stdlib since 1.8.0")
}
}
}
Alternatively, add this to your root-level build.gradle to apply it globally across all modules:
subprojects {
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.jetbrains.kotlin') {
details.useVersion '1.9.23' // pin to your project's Kotlin version
details.because 'Unify all Kotlin stdlib artifacts to avoid duplicate classes'
}
}
}
}
Fix 3: Use Gradle Resolution Strategy
Applicable when: Multiple libraries pull in different versions of the same dependency, and you need to force a single version across the board.
// app/build.gradle
android {
// ...
}
configurations.all {
resolutionStrategy {
// Force a single version of OkHttp across all transitive dependencies
force 'com.squareup.okhttp3:okhttp:4.12.0'
force 'com.squareup.okhttp3:logging-interceptor:4.12.0'
// Fail the build if two different versions of the same dependency are found
// (useful during development to catch conflicts early)
failOnVersionConflict()
}
}
Tip: Use failOnVersionConflict() in development builds to surface conflicts early, but remove it before production builds if you have transitive deps you cannot control.
Fix 4: Exclude Transitive Dependencies
Applicable when: A specific third-party library bundles a dependency you already declare, causing a direct duplicate.
Groovy DSL:
// app/build.gradle
dependencies {
implementation('com.some.third-party:sdk:2.0.0') {
// Exclude the bundled OkHttp since we manage our own version
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
}
// Our own explicitly managed version
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}
Kotlin DSL:
// app/build.gradle.kts
dependencies {
implementation("com.some.third-party:sdk:2.0.0") {
// Exclude the bundled OkHttp since we manage our own version
exclude(group = "com.squareup0.okhttp3", module = "okhttp")
}
// Our own explicitly managed version
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
To exclude a dependency globally from all configurations:
// root build.gradle or app/build.gradle
configurations.all {
exclude group: 'com.android.support', module: 'support-compat'
}
Fix 5: Use BOM (Bill of Materials) for Firebase / Compose
Applicable when: You are using Firebase, Jetpack Compose, or other Google libraries and manually specifying versions that conflict.
A BOM lets a single version coordinate all related library versions automatically — no more version mismatch duplicates.
Firebase BOM (recommended for all Firebase projects):
// app/build.gradle
dependencies {
// Import the Firebase BOM — manages all Firebase library versions
implementation platform('com.google.firebase:firebase-bom:33.1.0')
// Declare Firebase libraries WITHOUT version numbers
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-messaging'
}
Jetpack Compose BOM:
// app/build.gradle
dependencies {
// Import the Compose BOM
implementation platform('androidx.compose:compose-bom:2024.05.00')
// Declare Compose libraries WITHOUT version numbers
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.ui:ui-tooling-preview'
}
Why BOM works: The BOM defines a tested and compatible set of versions for all related libraries. Declaring a version yourself on top of a BOM import will always win — so if you add a BOM, remove explicit versions from BOM-managed libraries.
Fix 6: Run Dependency Insight Command
Applicable when: You are not sure which library is causing the conflict and need to diagnose before fixing.
Use the Gradle dependencyInsight task to trace exactly where a dependency is coming from:
# Find who is pulling in kotlin-stdlib-jdk8
./gradlew :app:dependencyInsight --dependency kotlin-stdlib-jdk8 --configurationreleaseRuntimeClasspath
# Find who is pulling in a support library
./gradlew :app:dependencyInsight --dependency support-fragment --configurationreleaseRuntimeClasspath
# Print the full dependency tree
./gradlew :app:dependencies --configuration releaseRuntimeClasspath > deps.txt
Reading the output:
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 (selected by rule)
\--- com.some.sdk:analytics:1.0.0
\--- releaseRuntimeClasspath
This tells you com.some.sdk:analytics:1.0.0 is pulling in an old kotlin-stdlib-jdk8. You can now either upgrade that SDK or apply an exclusion (Fix 4).
Key Takeaways
Quick Reference Checklist:
- Check gradle.properties for android.useAndroidX=true and android.enableJetifier=true
- Pin Kotlin stdlib version using dependency constraints if on Kotlin 1.8+
- Use ./gradlew :app:dependencies to inspect the full dependency tree
- Replace explicit Firebase/Compose versions with their respective BOMs
- Exclude duplicate transitive dependencies per-library or globally
- Run a clean build after any fix: ./gradlew clean assembleDebug
Pro Tip: Always run ./gradlew clean before rebuilding after dependency changes. Gradle’s
incremental build cache can sometimes mask whether a fix actually worked.
Reference Links
- Android Developers - Migrate to AndroidX
- Kotlin Stdlib Merge - JetBrains Blog (Kotlin 1.8)
- Gradle Dependency Resolution Rules
- Gradle Resolution Strategy - Official Docs
- Firebase Android BOM - Official Docs
- Jetpack Compose BOM - Official Docs
- Gradle dependencyInsight Task
- Android Gradle Plugin Release Notes


