Mr.AndroidShin / Dev Tools

Debugging log · Gradle

"Duplicate class" — the same library showed up twice

I added one new dependency and the build died with a wall of Duplicate class errors naming classes I'd never heard of. The new library wasn't the problem itself — it was that the same underlying library was now arriving through two different paths, and Gradle can't put the same class into the app twice.

The short version: two of your dependencies each pull in the same library (often at different versions). Find which two, then exclude the duplicate from one of them, or pin both to one version so only a single copy makes it into the build.

The error

Duplicate class com.example.thing.Foo found in modules
  library-a-1.2.0 (com.example:library-a:1.2.0) and
  library-b-3.0.0 (com.example:library-b:3.0.0)

The important part is the two module names at the end. They're the two dependencies that both contain Foo. One of them is bringing in a copy you don't need. Usually it's a transitive dependency — something you never asked for directly, pulled in behind the scenes by a library you did ask for.

Find where it comes from

Ask Gradle to print the dependency tree so you can see who's dragging in the duplicate:

./gradlew app:dependencies --configuration releaseRuntimeClasspath

Search the output for the duplicated artifact. You'll see it listed under two parents — those parents are the libraries you'll adjust. Now you have a choice: remove one copy, or make both use the same version.

Fix A — exclude the duplicate transitive dependency

If one library is pulling in an old copy you don't want, exclude it right where you declare that library:

implementation("com.example:library-b:3.0.0") {
    exclude(group = "com.example", module = "library-a")
}

Now only library-a from your other dependency survives, and the duplicate is gone. This is the most surgical fix when one side is clearly the odd one out.

Fix B — align both to one version

Sometimes both dependencies legitimately need the library, just at different versions. Force a single version so there's only one copy:

dependencies {
    implementation("com.example:library-a:1.2.0")
}
// or constrain it project-wide
configurations.all {
    resolutionStrategy {
        force("com.example:library-a:1.2.0")
    }
}

Pick a version both libraries can live with (usually the newer one) and the conflict resolves to a single artifact.

A very common special case: mixing old support-library artifacts with AndroidX. If the duplicated classes are android.support.* vs androidx.*, the real fix is to make sure android.useAndroidX=true and android.enableJetifier=true (or drop the last non-AndroidX dependency), not to exclude class by class.

How to confirm it's fixed

Group, module and version names above are placeholders — read the two module names in your own error and target those.