The Java compiler is throwing a "Duplicate Class" error because it’s encountering two or more class definitions with the exact same fully qualified name within the classpath. This isn’t a runtime issue; it’s a build-time problem where the compiler gets confused about which version of a class it should use, halting the build process entirely.

Here are the most common culprits and how to fix them:

1. Transitive Dependency Conflicts

This is by far the most frequent offender. You include library A, which depends on library B version 1.0. Later, you explicitly include library C, which also depends on library B, but this time it requires version 2.0. Maven (or Gradle) tries to resolve this, but if it can’t reconcile the versions or if both are somehow pulled in, you get duplicates.

Diagnosis: Run mvn dependency:tree (for Maven) or gradle dependencies (for Gradle). Look for the duplicated class name in the output. It will often show multiple paths to the same artifact, or different versions of the same artifact. For example, you might see com.example:mylib:1.0 and com.example:mylib:2.0 both listed.

Fix: Use your build tool’s dependency exclusion or management features.

  • Maven: Add an exclusion in your pom.xml within the dependency that’s bringing in the older or unwanted version of the conflicting library.

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>library-a</artifactId>
        <version>1.0.0</version>
        <exclusions>
            <exclusion>
                <groupId>com.example</groupId>
                <artifactId>conflicting-library-b</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    Alternatively, use dependency management to force a specific version:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>conflicting-library-b</artifactId>
                <version>2.0.0</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
  • Gradle: Use exclude in your build.gradle:

    implementation('com.example:library-a:1.0.0') {
        exclude group: 'com.example', module: 'conflicting-library-b'
    }
    

    Or force a version:

    configurations.all {
        resolutionStrategy {
            force 'com.example:conflicting-library-b:2.0.0'
        }
    }
    

Why it works: This tells your build tool to explicitly ignore or prefer a specific version of the problematic library, ensuring only one copy ends up on the classpath.

2. Including JARs Directly in the Project

Manually copying JAR files into a lib/ directory and then adding them to your project’s build path (e.g., via build.gradle’s files() or Maven’s system scope) is a recipe for disaster. If the same JAR is also managed by your dependency manager (Maven/Gradle), you’ll have two identical copies.

Diagnosis: Check your project structure for any manually placed JAR files in directories like lib/, libs/, or WEB-INF/lib. Also, inspect your pom.xml or build.gradle for dependencies declared using files() or system scope. Compare these against your declared Maven/Gradle dependencies.

Fix: Remove the manually added JAR files from your project directory. Ensure all necessary libraries are declared as proper dependencies in your pom.xml or build.gradle.

Why it works: This consolidates all dependencies under your build tool’s management, preventing manual duplication and ensuring a single, authoritative source for each library.

3. Duplicate Artifacts in Local Maven Repository

Sometimes, your local Maven repository (~/.m2/repository/) can get corrupted or contain duplicate versions of the same artifact, especially if you’ve had interrupted downloads or manual file copying.

Diagnosis: Navigate to the suspected directory in your local Maven repository (e.g., ~/.m2/repository/com/example/mylib/). If you see multiple subdirectories with slightly different version numbers or even the same version number appearing multiple times, this is the issue.

Fix: Delete the offending directories from your local Maven repository. Maven will then re-download them correctly on the next build. For example, delete ~/.m2/repository/com/example/mylib/1.0.0/.

Why it works: Forcing Maven to re-download ensures that the repository is clean and contains only the intended versions of the artifacts, eliminating local corruption.

4. Shade Plugin Issues (Especially for Application Bundling)

If you’re using plugins like the Maven Shade Plugin or Gradle Shadow Plugin to bundle dependencies into a single "fat JAR," misconfiguration can lead to duplicates. This often happens if the plugin tries to include a dependency that’s also present on the compile classpath directly, or if it incorrectly merges resources.

Diagnosis: Examine the configuration of your shade/shadow plugin in your pom.xml or build.gradle. Look for includes, excludes, and relocations sections. Check if you’re accidentally including dependencies that are already available at runtime in the target environment, or if you have conflicting createDependencyReducedPom configurations.

Fix: Carefully configure the shade plugin to only include necessary dependencies. Use <filters> in Maven Shade Plugin to exclude specific files or classes from being packaged.

  • Maven Shade Plugin Example:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.4</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>META-INF/*.SF</exclude>
                                <exclude>META-INF/*.DSA</exclude>
                                <exclude>META-INF/*.RSA</exclude>
                            </excludes>
                        </filter>
                    </filters>
                    <!-- Optional: relocate packages if needed -->
                    <relocations>
                        <relocation>
                            <pattern>com.example.internal</pattern>
                            <shadedPattern>com.example.shaded.internal</shadedPattern>
                        </relocation>
                    </relocations>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

Why it works: Proper filtering and relocation prevent the shade plugin from packaging duplicate classes or causing conflicts with classes that might already exist in the runtime environment.

5. Multi-Module Project Configuration Errors

In multi-module projects, if a module unintentionally declares a dependency that is already provided by another module (and not marked as provided scope), or if there are circular dependencies, you can get duplicate classes.

Diagnosis: Review the pom.xml or build.gradle files for each module. Pay close attention to the <scope> (Maven) or implementation/api (Gradle) declarations. Ensure that modules depending on each other correctly manage their shared dependencies. Use mvn help:effective-pom on each module to see the merged POM and identify what’s actually on the classpath.

Fix: Adjust dependency scopes. If module B depends on module A, and module C depends on module B, module A’s dependency should likely be provided or compileOnly in module B if it’s meant to be available at runtime by C. If module A is directly depended upon by C, ensure A is declared correctly in C’s POM.

Why it works: Correctly scoping dependencies ensures that shared libraries or modules are only included once in the final classpath, preventing duplicates introduced by redundant declarations across modules.

6. IDE Cache Corruption

Sometimes, your Integrated Development Environment (IDE) might have its own internal caches that become corrupted, leading it to report "duplicate class" errors even if the build tool’s classpath is clean.

Diagnosis: Try building your project from the command line using Maven (mvn clean install) or Gradle (gradle clean build). If the command-line build succeeds but the IDE still shows errors, it’s likely an IDE cache issue.

Fix: Most IDEs have an option to "Invalidate Caches and Restart." For IntelliJ IDEA, it’s under File > Invalidate Caches.... For Eclipse, you might need to delete the .metadata folder and re-import the project, or use Project > Clean....

Why it works: This clears out the IDE’s internal build artifacts and caches, forcing it to re-index and re-evaluate your project’s dependencies from scratch.

The next error you’ll likely encounter if you fix this, but haven’t addressed other underlying issues, is a ClassNotFoundException or NoClassDefFoundError if you’ve accidentally excluded a critical dependency.

Want structured learning?

Take the full Java course →