Question

How to Fix Duplicate Kotlin Stdlib Class Errors in Android Gradle

kotlinjavaandroiddependencies

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.0
  • org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.0
  • org.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.

Take Quiz

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:

implementation "androidx.core:core-ktx:1.10.1"

The + means "latest matching version," which can unexpectedly change your dependency graph and introduce incompatibilities.

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

  1. It reads your direct dependencies.
  2. It reads the transitive dependencies of each library.
  3. It builds one full dependency graph.
  4. It sees that:
    • kotlin-stdlib:1.8.0 contains classes already included in newer Kotlin packaging.
    • kotlin-stdlib-jdk7:1.6.0 and kotlin-stdlib-jdk8:1.6.0 also contain some of those same classes.
  5. During Android packaging, duplicate class names are detected.
  6. 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

How you fix it

  1. Add the Kotlin Android plugin if it is missing.
  2. Use fixed dependency versions instead of +.
  3. Check which library brings in old Kotlin stdlib artifacts.
  4. Exclude kotlin-stdlib-jdk7 and kotlin-stdlib-jdk8 if necessary.
  5. Sync Gradle and rebuild.

A practical cleaned-up version of the given file

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.google.gms.google-services'
}

android {
    compileSdk 33

    defaultConfig {
        applicationId "com.example.umfs"
        minSdk 21
        targetSdk 33
        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
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    buildFeatures {
        viewBinding true
    }

    namespace 'com.example.umfs'
}

dependencies {
    implementation platform('com.google.firebase:firebase-bom:32.7.4')

    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'androidx.core:core-ktx:1.10.1'
    implementation 'com.google.android.material:material:1.11.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'androidx.preference:preference-ktx:1.2.1'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
    implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
    implementation 'androidx.recyclerview:recyclerview:1.3.2'
    implementation 'androidx.cardview:cardview:1.0.0'

    implementation 'com.google.firebase:firebase-auth'
    implementation 'com.google.firebase:firebase-database'
    implementation 'com.google.firebase:firebase-firestore'
    implementation 'com.google.firebase:firebase-storage'

    implementation 'de.hdodenhof:circleimageview:3.1.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'

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

This version removes duplicates, avoids dynamic versions, and uses Firebase BoM correctly.

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-ktx but 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.
Take Quiz

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

Your sample has repeated or outdated declarations, such as:

  • firebase-firestore declared twice
  • firebase-database declared once with a version and again without one
  • firebase-core, which is no longer typically needed in modern setups

Cleaning these up reduces conflicts and confusion.

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:

implementation 'com.google.firebase:firebase-firestore:24.4.1'
implementation 'com.google.firebase:firebase-firestore:24.4.1'

This may not always break the build, but it makes the file harder to maintain.

5. Forgetting the Kotlin Android plugin

If you are using Kotlin libraries like core-ktx, your project should usually apply the Kotlin Android plugin.

plugins {
    id 'org.jetbrains.kotlin.android'
}

6. Fixing symptoms instead of finding the source

Beginners sometimes force-remove a dependency without checking which library needs it.

Use:

./gradlew app:dependencyInsight --dependency kotlin-stdlib-jdk8

That shows where the old library comes from.

Comparisons

ApproachWhat it doesGood forDownsides
Delete cache files manuallyRemoves local copies of dependenciesTemporary testing onlyDependencies are downloaded again; does not fix build config
Use fixed versionsMakes dependency graph predictableMost projectsRequires manual updates
Use dynamic versions like +Always uses a newer matching versionQuick experimentsCan introduce hidden conflicts
Exclude transitive dependenciesRemoves unwanted dependency pulled by another librarySpecific conflict resolutionCan break a library if excluded blindly
Use Firebase BoMAligns Firebase library versions automaticallyFirebase-based appsOnly manages Firebase artifacts
Force a version globallyMakes Gradle prefer one versionEmergency conflict cleanupCan hide deeper compatibility issues

kotlin-stdlib vs kotlin-stdlib-jdk7 / jdk8

LibraryPurposeImportant note
kotlin-stdlibCore Kotlin standard libraryNewer Kotlin setups often rely mainly on this
kotlin-stdlib-jdk7JDK 7 extensionsOlder setups may still pull it transitively
kotlin-stdlib-jdk8JDK 8 extensionsCan conflict with newer stdlib packaging when versions are mixed

BoM vs explicit versions for Firebase

StyleExampleRecommendation
Explicit versionsfirebase-auth:21.1.0Works, but harder to keep aligned
Firebase BoMimplementation platform('com.google.firebase:firebase-bom:32.7.4') + no versionsPreferred for Firebase projects
Take Quiz

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.android in 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

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'
}

First things to clean in the provided file

  • add Kotlin Android plugin
  • remove core-ktx:+
  • remove duplicate Firestore declaration
  • stop mixing BoM-managed and versioned Firebase dependencies
  • inspect who brings in Kotlin 1.6 stdlib modules

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.

Take Quiz

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

  1. Add the Kotlin Android plugin to the app module.
  2. Replace at least one dynamic dependency version with a fixed version.
  3. Remove duplicate dependency declarations.
  4. Convert Firebase dependencies to use the Firebase BoM consistently.
  5. Ensure the final dependencies block is clean and readable.
Take Quiz

Keep learning

Related questions

View more