skip to content

A class works locally but throws NoSuchMethodError in another environment. How do you use the dependency plugin goals to diagnose and fix the likely version conflict?

level: seniorimportance: must knowfreq 55%

answer

  1. NoSuchMethodError = two versions
  2. tree -Dverbose -Dincludes
  3. nearest-wins, not highest
  4. fix: dependencyManagement / direct / exclusion
  5. enforcer dependencyConvergence

basics

~20 s

A NoSuchMethodError usually means two versions of a library are in play. Run mvn dependency:tree -Dverbose -Dincludes=group:artifact to see which versions exist and who pulled them in, then fix it with an exclusion, a direct declaration, or dependencyManagement.

solid answer

~40 s

`NoSuchMethodError` at runtime typically means the compiled-against version differs from the runtime version — a classic dependency conflict. I'd run `mvn dependency:tree -Dverbose -Dincludes=group:artifact` to list every path to that artifact and see which versions mediation kept vs omitted (`-Dverbose` annotates omitted/conflict reasons). Maven's mediation is **nearest-wins**: the version at the shallowest depth in the tree wins, with declaration order breaking ties at equal depth. Once I know the conflict, I fix it deterministically by pinning the version in **`<dependencyManagement>`** (best for consistency), declaring the dependency directly to make it nearest, or adding an `<exclusion>` to the offender. I'd confirm with `dependency:tree` again and use `dependency:analyze` to ensure I'm declaring what I actually use. If environments differ, I'd check that both build the same resolved tree (same settings.xml/repos, no stale `.m2`).

code

bash · 1 line
bash
mvn dependency:tree -Dverbose -Dincludes=com.google.guava:guava

go deeper

for a junior

Can run dependency:tree and spot two versions of the same library.

for a middle

Knows nearest-wins and applies an exclusion or direct declaration to fix it.

for a senior

Diagnoses with -Dverbose, chooses dependencyManagement for consistency, and verifies across environments.

for a principal

Mandates enforcer convergence rules and BOM-based version governance to prevent conflicts org-wide.

## Symptom and cause `NoSuchMethodError` / `NoClassDefFoundError` for a method that exists in your IDE but not at runtime almost always means **two versions** of a library are involved: you compiled against version A but version B (missing the method) is on the runtime classpath. This is a **version conflict** resolved unexpectedly. ## Maven version mediation: nearest-wins When the graph contains multiple versions of the same `groupId:artifactId`, Maven picks **one** by the **nearest-wins** rule: - The version at the **shallowest depth** from the root wins. - At **equal depth**, the one **declared first** wins (declaration order). Maven does *not* pick the highest version automatically. So a deep transitive newer version can lose to a shallow older one. ## Diagnose with dependency:tree ```bash mvn dependency:tree -Dverbose -Dincludes=com.google.guava:guava ``` - Lists every branch leading to guava. - `-Dverbose` shows omitted nodes with reasons like `(omitted for conflict with 31.1-jre)`, revealing the loser. - Now you know which version won and who introduced each. Then `mvn dependency:analyze` confirms whether you actually use the artifact directly (so you should declare it) vs only transitively. ## Fixes (deterministic) 1. **dependencyManagement** — pin the version centrally; applies regardless of tree depth. Best for multi-module consistency: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>33.0.0-jre</version> </dependency> </dependencies> </dependencyManagement> ``` 2. **Direct declaration** — declare it at depth 1 so nearest-wins selects your version. 3. **Exclusion** — strip the unwanted transitive version from the offending dependency: ```xml <dependency> <groupId>com.example</groupId> <artifactId>offender</artifactId> <exclusions> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency> ``` ## Verify and prevent - Re-run `dependency:tree` to confirm one version now. - Consider the **maven-enforcer-plugin** `dependencyConvergence` rule to fail the build on divergent versions. - Ensure environments resolve identically: same `settings.xml`/mirrors, and no corrupt/stale `.m2` (a `purge-local-repository` or `-U` rules that out). ## Why environments differ Different settings.xml, repository mirrors, profiles, or a stale local cache can produce different resolved trees, which is why 'works on my machine' happens.

  • Does Maven pick the highest version on conflict?
    No. It uses nearest-wins: shallowest depth from the root wins, with declaration order breaking ties at equal depth. A higher version deeper in the tree can lose.
  • Which fix is best for multi-module consistency, and why?
    <dependencyManagement>, because it pins the version centrally regardless of where the dependency appears in the tree, so all modules converge on the same version.
  • How do you prevent these conflicts from recurring in CI?
    Add the maven-enforcer-plugin dependencyConvergence rule to fail the build when multiple versions of the same artifact are resolved.

saying these in an interview costs you the question

  • Saying Maven resolves to the highest version
  • Fixing only by deleting the local cache without addressing the version mediation
  • Ignoring -Dverbose so you never see the losing version
  • Assuming the two environments resolve the same tree

context