Question
How to Fix Duplicate Kotlin Stdlib Class Errors in Android Gradle
Question
I am getting duplicate class errors in my Kotlin Android project during the build.
Under the org.jetbrains.kotlin libraries, it looks like different Kotlin dependencies are being pulled in, including kotlin-stdlib, kotlin-stdlib-jdk7, and kotlin-stdlib-jdk8. I think the issue is caused by having multiple Kotlin standard library versions at the same time, but I am not sure how to remove the conflicting dependency correctly from my project.
For example, the build shows errors like these:
Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules jetified-kotlin-stdlib-1.8.0 (org.jetbrains.kotlin:kotlin-stdlib:1.8.0) and jetified-kotlin-stdlib-jdk8-1.6.0 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0)
Duplicate class kotlin.internal.jdk7.JDK7PlatformImplementations found in modules jetified-kotlin-stdlib-1.8.0 (org.jetbrains.kotlin:kotlin-stdlib:1.8.0) and jetified-kotlin-stdlib-jdk7-1.6.0 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.0)
I also tried deleting files from the local org.jetbrains.kotlin folder, but Android Studio downloads them again the next time I build.
This is my app-level build.gradle file:
plugins {
id 'com.android.application'
id 'com.google.gms.google-services'
}
android {
compileSdk 33
defaultConfig {
applicationId "com.example.umfs"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
namespace 'com.example.umfs'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.firebase:firebase-database:20.1.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'com.google.firebase:firebase-auth:21.1.0'
implementation 'com.google.firebase:firebase-core:21.1.1'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation 'com.google.firebase:firebase-firestore:24.4.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.firebase:firebase-firestore:24.4.1'
implementation 'com.google.firebase:firebase-storage:20.1.0'
implementation 'com.google.firebase:firebase-database'
implementation platform('com.google.firebase:firebase-bom:28.4.0')
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.makeramen:roundedimageview:2.3.0'
implementation 'com.github.bumptech.glide:glide:4.14.2'
implementation 'com.github.marlonlom:timeago:4.0.3'
implementation "androidx.core:core-ktx:+"
}
apply plugin: 'com.google.gms.google-services'
How can I fix this dependency conflict properly in Gradle?
Short Answer
By the end of this page, you will understand what a duplicate class error means in an Android Gradle build, why Kotlin stdlib version conflicts happen, and how to fix them by aligning dependency versions instead of deleting downloaded files.
Concept
A duplicate class error happens when Gradle resolves two different libraries that both contain the same compiled class name. During the Android build, only one definition of a class can exist on the classpath. If two artifacts provide the same class, the build fails.
In this case, the conflict is between:
org.jetbrains.kotlin:kotlin-stdlib:1.8.0org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.0org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0
This matters because newer Kotlin versions merged or reorganized parts of the standard library. If your project or one of your dependencies pulls in an older jdk7 or jdk8 stdlib artifact while another dependency uses a newer base stdlib, Gradle may end up with overlapping classes.
A key point: the problem is not the files in your local cache. Those files are just downloaded copies of declared dependencies. Deleting them does not solve the real issue, because Gradle simply downloads them again based on your build configuration.
The real fix is to:
- identify which dependency introduces the old Kotlin libraries
- align Kotlin-related versions
- avoid dynamic versions such as
+ - use modern Gradle dependency management consistently
In Android projects, dependency issues often come from transitive dependencies. That means you may not have added kotlin-stdlib-jdk8 directly, but another library may have brought it in for you.
Mental Model
Think of your app build like packing a suitcase for a trip.
- Each dependency is an item you pack.
- Each class is a specific object inside the suitcase.
- If two different bags both contain the exact same object with the same label, security stops you and asks which one is the real one.
That is what Gradle is doing.
Deleting the downloaded files is like removing the object from the suitcase after packing, while your packing list still says to include it. On the next pack, it comes back.
So the correct solution is not to delete files manually. The correct solution is to fix the packing list: your Gradle dependencies.
Syntax and Examples
In Gradle, dependency conflicts are usually fixed by declaring consistent versions or excluding conflicting transitive dependencies.
Example: a clean Kotlin Android dependency setup
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
}
android {
compileSdk 33
defaultConfig {
applicationId "com.example.app"
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.0"
implementation "androidx.core:core-ktx:1.10.1"
}
Why this helps
- The Kotlin Android plugin is applied explicitly.
- Kotlin uses a known version instead of mixed versions.
core-ktx:+is replaced with a fixed version.- Fixed versions make builds predictable.
Example: excluding old Kotlin stdlib artifacts
If a library brings in old Kotlin artifacts, you can exclude them:
implementation('some.library:example:1.0.0') {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
}
Use this only when needed. Usually, version alignment is a better first step.
Safer version declarations
Avoid this:
implementation "androidx.core:core-ktx:+"
Prefer this:
Step by Step Execution
Consider this simplified dependency situation:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.0"
implementation "some.library:example:1.0.0"
}
Assume some.library:example:1.0.0 transitively depends on:
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.0
What Gradle does
- It reads your direct dependencies.
- It reads the transitive dependencies of each library.
- It builds one full dependency graph.
- It sees that:
kotlin-stdlib:1.8.0contains classes already included in newer Kotlin packaging.kotlin-stdlib-jdk7:1.6.0andkotlin-stdlib-jdk8:1.6.0also contain some of those same classes.
- During Android packaging, duplicate class names are detected.
- The build fails.
How you investigate
A common Gradle command is:
./gradlew app:dependencies
This prints the dependency tree so you can see which library pulls in the old Kotlin modules.
You can also inspect one dependency path more closely with:
./gradlew app:dependencyInsight --dependency kotlin-stdlib
Real World Use Cases
Dependency conflict resolution is common in real Android development.
Typical situations
- Adding Firebase and AndroidX libraries together: different libraries may expect different Kotlin versions.
- Updating one library but not others: one dependency becomes newer while another still depends on older Kotlin artifacts.
- Using dynamic versions such as
+: a dependency updates silently and introduces a mismatch. - Large team projects: different modules may declare slightly different versions of the same library.
- Migrating Java apps to Kotlin: Kotlin plugins and libraries may not be configured consistently at first.
Practical examples
- A chat app adds a new image library and suddenly gets duplicate Kotlin classes.
- An ecommerce app updates
core-ktxbut leaves older navigation or Firebase dependencies. - A multi-module app has one module on Kotlin 1.8 and another indirectly using Kotlin 1.6 artifacts.
Real Codebase Usage
In real projects, developers rarely solve this by deleting cache files. They solve it in the build configuration.
Common patterns
1. Version alignment
Keep Kotlin, AndroidX, and other core libraries on compatible versions.
implementation "androidx.core:core-ktx:1.10.1"
2. Avoid dynamic versions
Dynamic versions make builds unstable.
// Avoid
implementation "androidx.core:core-ktx:+"
// Prefer
implementation "androidx.core:core-ktx:1.10.1"
3. Use platform dependencies correctly
Firebase BoM lets you omit versions for Firebase libraries.
implementation platform('com.google.firebase:firebase-bom:32.7.4')
implementation 'com.google.firebase:firebase-auth'
implementation 'com.google.firebase:firebase-firestore'
4. Exclude transitive dependencies selectively
If one library pulls in an outdated module, exclude it.
implementation('library:example:1.0.0') {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
}
5. Inspect the dependency graph
Developers use Gradle reports to locate the exact source of a conflict.
./gradlew app:dependencies
./gradlew app:dependencyInsight --dependency kotlin-stdlib-jdk8
6. Remove obsolete or duplicate dependencies
Common Mistakes
1. Deleting files from the Gradle cache
This does not fix the root cause.
.idea/libraries
.gradle/caches
Gradle downloads dependencies again because they are still declared in the build.
Better approach: fix the dependency graph in build.gradle.
2. Using dynamic versions
Broken pattern:
implementation "androidx.core:core-ktx:+"
Why it is risky:
- builds are not reproducible
- dependency versions can change unexpectedly
- new versions may pull in conflicting transitive dependencies
Use a fixed version instead:
implementation "androidx.core:core-ktx:1.10.1"
3. Mixing versioned and BoM-managed Firebase dependencies
Broken pattern:
implementation 'com.google.firebase:firebase-database:20.1.0'
implementation platform('com.google.firebase:firebase-bom:28.4.0')
implementation 'com.google.firebase:firebase-database'
This is inconsistent.
Pick one style: if you use the Firebase BoM, omit versions for Firebase libraries.
4. Declaring the same dependency twice
Example from the provided file:
Comparisons
| Approach | What it does | Good for | Downsides |
|---|---|---|---|
| Delete cache files manually | Removes local copies of dependencies | Temporary testing only | Dependencies are downloaded again; does not fix build config |
| Use fixed versions | Makes dependency graph predictable | Most projects | Requires manual updates |
Use dynamic versions like + | Always uses a newer matching version | Quick experiments | Can introduce hidden conflicts |
| Exclude transitive dependencies | Removes unwanted dependency pulled by another library | Specific conflict resolution | Can break a library if excluded blindly |
| Use Firebase BoM | Aligns Firebase library versions automatically | Firebase-based apps | Only manages Firebase artifacts |
Cheat Sheet
Duplicate class error quick reference
What it means
Two dependencies contain the same class, so the Android build cannot decide which one to use.
Common causes
- mixed Kotlin versions
- transitive dependency conflicts
- dynamic versions like
+ - duplicate or inconsistent library declarations
Useful Gradle commands
./gradlew app:dependencies
./gradlew app:dependencyInsight --dependency kotlin-stdlib
./gradlew app:dependencyInsight --dependency kotlin-stdlib-jdk8
Good practices
- use fixed versions
- apply
org.jetbrains.kotlin.androidin Kotlin Android apps - use Firebase BoM consistently
- remove duplicate dependency lines
- exclude old transitive artifacts only when necessary
Avoid
implementation "androidx.core:core-ktx:+"
Prefer
implementation "androidx.core:core-ktx:1.10.1"
Firebase BoM pattern
implementation platform('com.google.firebase:firebase-bom:32.7.4')
implementation 'com.google.firebase:firebase-auth'
implementation 'com.google.firebase:firebase-firestore'
Exclude old Kotlin stdlib modules if needed
FAQ
Why does deleting the Kotlin files not solve the problem?
Because those files are only cached copies of dependencies declared in Gradle. When you build again, Gradle downloads them again.
What causes duplicate Kotlin stdlib classes?
Usually a version mismatch, such as one dependency using kotlin-stdlib:1.8.0 while another pulls in kotlin-stdlib-jdk7 or kotlin-stdlib-jdk8 from an older version.
Should I remove kotlin-stdlib or kotlin-stdlib-jdk8 manually?
Not from the cache. You should fix the dependency declarations or exclude the transitive dependency in Gradle.
Is core-ktx:+ a bad idea?
Yes, in most real projects. It can upgrade silently and introduce dependency conflicts.
Do I need firebase-core?
In modern Firebase Android projects, it is usually unnecessary. The Firebase BoM and specific Firebase libraries are typically enough.
How do I find which library adds the old Kotlin dependency?
Run:
./gradlew app:dependencyInsight --dependency kotlin-stdlib-jdk8
This shows the dependency path.
Should I use Firebase BoM or explicit Firebase versions?
Usually Firebase BoM is the better choice because it keeps Firebase libraries aligned automatically.
Mini Project
Description
Create a small Android Gradle cleanup exercise where you take a messy dependency list and make it consistent. This project demonstrates how to identify duplicate declarations, replace dynamic versions, and align Kotlin- and Firebase-related dependencies to prevent duplicate class errors.
Goal
Clean an Android app module so it uses consistent, predictable dependency versions and builds without duplicate class conflicts.
Requirements
- Add the Kotlin Android plugin to the app module.
- Replace at least one dynamic dependency version with a fixed version.
- Remove duplicate dependency declarations.
- Convert Firebase dependencies to use the Firebase BoM consistently.
- Ensure the final
dependenciesblock is clean and readable.
Keep learning
Related questions
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.
Can You Extend a Data Class in Kotlin? Inheritance, Limits, and Better Alternatives
Learn why Kotlin data classes cannot be extended, what causes the component function clash, and which alternatives to use instead.
Difference Between List and Array in Kotlin
Learn the difference between List and Array in Kotlin, including mutability, size, APIs, performance, and when to use each one.