← Debugging Guides

阅读中文版本

Maven NoSuchMethodError — Dependency Version Conflict

Fix NoSuchMethodError and NoClassDefFoundError from conflicting transitive dependencies by inspecting the dependency tree and pinning via dependencyManagement.

advanceddebuggingjavamavendependencies

Symptoms

  • Runtime throws NoSuchMethodError or NoClassDefFoundError although it compiles
  • The error names a method that exists in a newer version of a library
  • Behavior differs between the IDE and the packaged jar

Possible causes

  • Two versions of the same library are on the classpath and the older wins
  • Maven nearest-wins mediation picks a transitive version you did not expect
  • A shaded or relocated dependency was not relocated in the final artifact

Diagnosis steps

Inspect the dependency tree for duplicates

mvn dependency:tree -Dincludes=com.google.guava:guava

Interpretation

Multiple nodes for one artifact with different versions reveal the conflict.

Find who pulls the older version

mvn dependency:tree -Dverbose | grep -B 3 "guava:jar:20"

Interpretation

The verbose tree shows omitted versions and the path that introduced them.

Verify what is on the runtime classpath

mvn dependency:build-classpath -Dmdep.outputFile=cp.txt && grep -o "guava[^:]*" cp.txt

Interpretation

The actual runtime classpath, not the IDE, determines which version loads.

Root cause

Maven resolves a single version per artifact using nearest-wins (and first-declared on ties). A transitive older version can therefore override your direct newer one, so code compiled against the newer API fails at runtime with NoSuchMethodError.

Fix

Pin the version with dependencyManagement or a direct dependency, exclude the offending transitive path, and rebuild the tree to confirm one version remains.

Risk note

Pinning a version that other libraries depend on can break their API expectations; verify each consumer after pinning.

Verify the fix

Rebuild the tree and confirm exactly one version resolves; run the failing code path and confirm no NoSuchMethodError, then run the full test suite.

Symptoms

When you hit “Maven NoSuchMethodError — Dependency Version Conflict”, guessing wastes time. The guide below follows evidence: reproduce the symptom, run targeted diagnostics, identify the root cause, apply the fix, and verify it with concrete checks.

Observed symptoms include:

  • Runtime throws NoSuchMethodError or NoClassDefFoundError although it compiles
  • The error names a method that exists in a newer version of a library
  • Behavior differs between the IDE and the packaged jar

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Inspect the dependency tree for duplicates

mvn dependency:tree -Dincludes=com.google.guava:guava

Multiple nodes for one artifact with different versions reveal the conflict.

Step 2: Find who pulls the older version

mvn dependency:tree -Dverbose | grep -B 3 "guava:jar:20"

The verbose tree shows omitted versions and the path that introduced them.

Step 3: Verify what is on the runtime classpath

mvn dependency:build-classpath -Dmdep.outputFile=cp.txt && grep -o "guava[^:]*" cp.txt

The actual runtime classpath, not the IDE, determines which version loads.

Likely contributors, in order of frequency:

  • Two versions of the same library are on the classpath and the older wins
  • Maven nearest-wins mediation picks a transitive version you did not expect
  • A shaded or relocated dependency was not relocated in the final artifact

Root Cause

Maven resolves a single version per artifact using nearest-wins (and first-declared on ties). A transitive older version can therefore override your direct newer one, so code compiled against the newer API fails at runtime with NoSuchMethodError.

The Fix

Pin the version with dependencyManagement or a direct dependency, exclude the offending transitive path, and rebuild the tree to confirm one version remains.

Watch out: Pinning a version that other libraries depend on can break their API expectations; verify each consumer after pinning.

<!-- pom.xml: force a single, known-good version -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>33.0.0-jre</version>
    </dependency>
  </dependencies>
</dependencyManagement>

<!-- or exclude the offending transitive path -->
<exclusions>
  <exclusion>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
  </exclusion>
</exclusions>

Verify and Prevent

Rebuild the tree and confirm exactly one version resolves; run the failing code path and confirm no NoSuchMethodError, then run the full test suite.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.