🔴 The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOG// DOC-DERIVED — canonical shape of the Guava Preconditions clash (Hadoop/Spark builds mixing guava 11/12 with guava 20+): Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkState(ZLjava/lang/String;J)V at org.apache.hadoop.metrics2.lib.MetricsRegistry.newCounter(MetricsRegistry.java:231) at com.devinhyderabad.report.ReportJob.buildQuery(ReportJob.java:42) at com.devinhyderabad.report.ReportJob.main(ReportJob.java:18)

⚡ Quick Fix Works 80% of the time

Run dependency:tree filtered to the package prefix from the message, exclude the stale transitive jar wherever it leaks in, and pin one version for the whole build.

mvn -q dependency:tree -Dincludes=com.google.guava <!-- then exclude the stale copy at the dependency that drags it in --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <exclusions> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency>

🧠 Why this Happens

Tap to expand the deep technical explanation

javac does not embed method calls; it records a symbolic reference made of class name, method name, and descriptor. The descriptor here decodes as checkState(boolean, String, long): Z is boolean, Ljava/lang/String; is String, J is long. At the first invocation the JVM resolves that reference against whatever Preconditions class the classpath actually served up. Two jars both define com.google.common.base.Preconditions; the older one won the ordering race and simply has no overload taking a long. Class loading succeeded while member resolution failed — which is exactly why this lands in the LinkageError family and not as a ClassNotFoundException.

The HITEC City Parking Spot Analogy:

You dial the company switchboard without a problem, but extension 47-J rings into nothing — the building is reachable, the desk you were promised no longer exists.

🔁 How to Reproduce Confirm this is your error

Compile any module against Guava 20+ (which added the long-parameter checkState overload, @since 20.0), then place Guava 19 or older earlier on the runtime classpath. The first call site throws before the job does anything useful. Wording has been stable since Java 5 — DOC-DERIVED, no lab capture needed.

🛠️ Solutions (5 Ways to Fix)

Solution 1✓ Most common cause

Let dependency:tree name the winner, then exclude the stale transitive

👉 Use this if Maven or Gradle manages the project and the missing method belongs to a third-party library.

Maven nearest-wins decided which duplicate shipped. The tree lists every path to the artifact; cut every path carrying the wrong version so exactly one survives, then rebuild.

mvn -q dependency:tree -Dincludes=com.google.guava <!-- winner identified? exclude the loser wherever it leaks in --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <exclusions> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency>
Solution 2

Pin one version for the whole build with dependencyManagement or a BOM

👉 Use this when several modules of the same repo each declare their own version of the clashing library.

Central management forces every module to compile and test against one binary. A BOM import keeps versions aligned even when third-party starters drag their own choices in behind you.

<dependencyManagement> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>33.2.1-jre</version> </dependency> </dependencies> </dependencyManagement>
Solution 3

Break the build on conflicts with Maven Enforcer dependencyConvergence

👉 Use this if you want the clash caught in CI instead of by customers at 3 a.m.

The convergence rule fails the build whenever two paths disagree about a version and prints both offenders. Fixing drift while it is still a merge request costs minutes, not outages.

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <executions> <execution> <goals><goal>enforce</goal></goals> <configuration> <rules> <dependencyConvergence/> </rules> </configuration> </execution> </executions> </plugin>
Solution 4

Audit the fat jar you actually deploy

👉 Use this if the job ships as an Uber-JAR, shaded artifact, or Spring Boot executable where build-tool trees stop reflecting what runs.

After shading, the archive is the only truth. Count how many copies of the guilty package made it inside, then dedupe or relocate them so exactly one binary version exists.

unzip -l target/app.jar | grep -c "com/google/common/base" # more than one hit? dedupe with maven-shade-plugin or relocate: # <relocations> # <relocation> # <pattern>com.google.common</pattern> # <shadedPattern>shaded.guava</shadedPattern> # </relocation> # </relocations>
Solution 5

When the missing member lives in the JDK itself: the ByteBuffer.flip() trap

👉 Use this if the trace names a JDK class such as java.nio.ByteBuffer.flip() instead of a third-party jar.

Java 9 gave flip() a covariant override returning ByteBuffer instead of Buffer. Code compiled on Java 9+ records the new descriptor; running that bytecode on a Java 8 JRE fails resolution at the first flip(). Rebuild against the oldest runtime you support instead of guessing at flags.

# rebuild targeting the oldest supported runtime - production-safe flag mvn -Dmaven.compiler.release=8 clean package # Gradle equivalent: # tasks.withType(JavaCompile) { options.release = 8 }

📋 Version Notes

Java 8

flip() still returns Buffer — this cross-version descriptor skew was born here and still bites 8-vs-11 fleets.

Java 11

--release cross-compilation exists since 9; plain classpath jars remain completely unpolicied.

Java 17

JPMS still guards only module-path reads; the failure mode on the classpath is identical.

Java 21

Unchanged — dependency tooling remains the only real guardrail.

🛡️ How to Prevent This Next Time

Manage every third-party version centrally (BOM plus Enforcer or Gradle constraints), never drop raw jars into lib folders, and build the exact deployable in CI so local classpath drift cannot hide between builds.