Fix: Java NoSuchMethodError
Part of: Java & JVM Errors
Quick Answer
How to fix Java NoSuchMethodError caused by classpath conflicts, incompatible library versions, wrong dependency scope, shaded JARs, and compile vs runtime version mismatches.
The Error
You run a Java application and get:
Exception in thread "main" java.lang.NoSuchMethodError:
'void com.google.gson.GsonBuilder.setStrictness(com.google.gson.Strictness)'Or variations:
java.lang.NoSuchMethodError: org.apache.commons.lang3.StringUtils.isBlank(Ljava/lang/CharSequence;)Zjava.lang.NoSuchMethodError: 'java.util.List com.example.UserService.findAll()'NoSuchMethodError: 'void org.slf4j.Logger.atDebug()'The JVM found the class but the method you are calling does not exist in it. The code was compiled against one version of a library but is running with a different version that does not have that method.
Why This Happens
Java compiles method calls into bytecode that references the exact method signature (name, parameter types, return type). At runtime, the JVM loads the class and looks for that exact method. If the runtime class has a different version than the compile-time class, the method might not exist.
This is different from ClassNotFoundException (class not found at all) and NoClassDefFoundError (class found at compile time but missing at runtime). With NoSuchMethodError, the class is found but the specific method is missing.
Common causes:
- Dependency version conflict. Two libraries require different versions of the same dependency, and Maven/Gradle picks the wrong one.
- Stale compiled classes. You updated a dependency but did not recompile the code that uses it.
- Shaded/fat JAR conflict. A shaded JAR bundles an old version of a library that conflicts with a newer version on the classpath.
- Classpath ordering. The wrong version of a JAR is loaded first.
- JDK version mismatch. A method exists in JDK 17 but not in JDK 11.
The reason the JVM can run a class that is “wrong” is that bytecode references methods by their symbolic descriptor — package, class name, method name, parameter types, return type — but the actual resolution happens lazily at the call site, not at class load time. The class loader loads com.google.gson.GsonBuilder successfully because the class file exists. The method lookup only happens when your code actually calls setStrictness(...). If the version of GsonBuilder on the runtime classpath was compiled before that method existed (or with a different parameter type), the lookup fails with NoSuchMethodError. The error therefore points at the calling code, not at the library — which makes triage harder than it should be.
This is also why NoSuchMethodError is almost always a build pipeline failure, not a code failure. The code is fine: it compiled cleanly against one version of the library. The deploy artifact contains a different version. Somewhere between “developer’s laptop” and “production JVM,” dependency resolution drifted. That drift is the thing to fix, not the call site.
In Production: Incident Lens
NoSuchMethodError in production is one of the most embarrassing failure modes because it almost always means the build worked on someone’s machine but the production artifact is structurally wrong. The whole thing should have been caught before deployment.
- How it surfaces: Almost always at application startup. Spring Boot, Micronaut, and Quarkus apps throw it during bean initialization, the application context fails to start, and the process exits non-zero. In long-running apps it can also surface on the first request that exercises a particular code path — the class wasn’t loaded until needed. The stack trace names the calling class and line, plus the missing method signature, which together pinpoint the conflicting dependency pair within minutes.
- Blast radius: 100% of pods running the broken image, immediately, unless a canary deploy gated the rollout. Because the error fires at startup, every replica crashes the same way at the same time. Without canary or rolling-deploy health gating, the orchestrator promotes the broken image globally before any human notices.
- What catches it: Container startup health checks (readiness/liveness probes), application startup time SLOs, and APM startup failures. Sentry/Rollbar may catch it if instrumentation initialized before the failing call, but most often the JVM dies before the error reporter flushes. The most reliable signal is “new replicas are not passing readiness” — that is your alert.
- Recovery sequence: Rollback the deploy immediately. Forward-fix is the wrong default here because the root cause is a dependency mismatch that is faster to debug locally than under deployment pressure. After rollback, reproduce by pulling the exact image and running it:
docker run --rm <image>should fail the same way. Then runmvn dependency:treeor./gradlew dependenciesagainst the committed lockfile to see which version actually ended up on the classpath. - Postmortem preventive: Three durable controls. First, add a dependency convergence check in CI (
maven-enforcer-pluginwithDependencyConvergence, GradlefailOnVersionConflict()). It fails the build when two transitive paths resolve different versions of the same artifact. Second, run a startup smoke test on the built artifact in CI (java -jar build/libs/app.jarwith--server.port=0and a quick readiness check). Third, canary deploy with health-check gating so a broken image cannot promote past one pod.
Fix 1: Find the Conflicting Dependency
Identify which version of the library is actually being loaded at runtime:
Maven — show the dependency tree:
mvn dependency:treeLook for the library mentioned in the error. If you see multiple versions:
[INFO] +- com.example:my-app:jar:1.0
[INFO] | +- com.google.code.gson:gson:jar:2.8.9:compile
[INFO] +- com.other:library:jar:2.0
[INFO] | +- com.google.code.gson:gson:jar:2.10.1:compile (version managed from 2.8.9)Gradle — show dependencies:
./gradlew dependencies --configuration runtimeClasspathFind which JAR is loaded at runtime:
System.out.println(SomeClass.class.getProtectionDomain().getCodeSource().getLocation());This prints the JAR path that contains the class, revealing which version is loaded.
Pro Tip: Always check the runtime classpath, not just the compile classpath. A method might exist at compile time but the runtime classpath loads a different version. Use
-verbose:classJVM flag to see which classes are loaded from which JARs:java -verbose:class -jar app.jar 2>&1 | grep "SomeClass"
Fix 2: Force the Correct Dependency Version
Maven — use <dependencyManagement>:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</dependencyManagement>This forces all transitive dependencies to use version 2.10.1.
Maven — exclude the wrong version:
<dependency>
<groupId>com.other</groupId>
<artifactId>library</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>Then add the correct version as a direct dependency.
Gradle — force a version:
configurations.all {
resolutionStrategy {
force("com.google.code.gson:gson:2.10.1")
}
}Gradle — exclude:
implementation("com.other:library:2.0") {
exclude(group = "com.google.code.gson", module = "gson")
}If Maven fails to resolve dependencies at all (rather than picking the wrong version), the issue is repository access or a missing artifact, not a method conflict.
Fix 3: Clean and Rebuild
Stale compiled classes can cause NoSuchMethodError when the dependency changed but your code was not recompiled:
Maven:
mvn clean packageGradle:
./gradlew clean buildIntelliJ IDEA:
Build → Rebuild Project (not just Build, which is incremental).
Delete build caches manually:
rm -rf target/ # Maven
rm -rf build/ # Gradle
rm -rf out/ # IntelliJ
rm -rf ~/.gradle/caches/ # Gradle global cache (nuclear option)Common Mistake: Running
mvn packagewithoutcleanafter changing dependency versions. Maven’s incremental compilation does not always recompile classes affected by dependency changes. Always usemvn clean packagewhen dependency versions change.
Fix 4: Check for Shaded JAR Conflicts
Shaded (fat/uber) JARs bundle dependencies inside them. If a shaded JAR contains an old version of a library, it conflicts with the correct version on the classpath:
Diagnose:
# List classes in a JAR
jar tf my-shaded-app.jar | grep "gson"If the shaded JAR contains com/google/gson/GsonBuilder.class, it is bundling Gson. The shaded copy might be an older version.
Fix: Relocate packages in the shade plugin:
Maven Shade Plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<relocations>
<relocation>
<pattern>com.google.gson</pattern>
<shadedPattern>shaded.com.google.gson</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>Relocation moves the bundled classes to a different package, preventing conflicts with the non-shaded version.
Fix 5: Fix JDK Method Availability
Some methods only exist in newer JDK versions:
// Java 11+ only:
String result = " hello ".strip();
// Java 9+ only:
List<String> list = List.of("a", "b", "c");
// Java 16+ only:
record User(String name, int age) {}Check your runtime JDK version:
java -versionFix: Update the JDK to match the version the code was compiled for. See Fix: Java UnsupportedClassVersionError for JDK version management.
Fix: Use compatible alternatives for older JDKs:
// Instead of String.strip() (Java 11+):
String result = " hello ".trim(); // Java 1.0+
// Instead of List.of() (Java 9+):
List<String> list = Arrays.asList("a", "b", "c"); // Java 5+
List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));Fix 6: Fix Spring Boot Dependency Conflicts
Spring Boot manages dependency versions through its BOM (Bill of Materials). Overriding a managed version can cause NoSuchMethodError:
Check Spring Boot’s managed versions:
mvn help:effective-pom | grep "gson"Override safely with Spring Boot properties:
<properties>
<gson.version>2.10.1</gson.version>
</properties>Spring Boot property overrides are the safest way to change managed dependency versions because they update all related dependencies consistently.
Do NOT force incompatible versions:
If Spring Boot 3.x manages Jackson 2.15 and you force Jackson 2.10, Spring’s own code might call methods that only exist in 2.15. Stick to compatible version ranges.
Fix 7: Debug with Reflection
When the error message is unclear about which method is missing, use reflection to check:
import java.lang.reflect.Method;
for (Method method : SomeClass.class.getDeclaredMethods()) {
System.out.println(method);
}This lists all methods available in the class at runtime. Compare with what your code expects to find the mismatch.
Check the exact method signature:
try {
Method m = SomeClass.class.getMethod("methodName", String.class, int.class);
System.out.println("Found: " + m);
} catch (NoSuchMethodException e) {
System.out.println("Method not found!");
// List available methods for debugging
for (Method m : SomeClass.class.getMethods()) {
if (m.getName().contains("method")) {
System.out.println(" Available: " + m);
}
}
}Fix 8: Fix Test vs Runtime Classpath
A method might exist in the test classpath but not in the runtime classpath, or vice versa:
Maven scope issues:
<!-- This is only available during tests: -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>If a class from a test-scoped dependency is accidentally used in production code, it compiles but fails at runtime with NoSuchMethodError or ClassNotFoundException.
Fix: Check dependency scopes:
mvn dependency:tree -Dscope=runtime
mvn dependency:tree -Dscope=testCompare the two trees to find dependencies that are only in the test scope.
Still Not Working?
Check for class loading order. In application servers (Tomcat, JBoss, WildFly), the class loading order differs from standalone applications. The server might load its own version of a library before yours.
Check for OSGi bundle issues. In OSGi environments (Eclipse, Karaf), each bundle has its own classloader. A method might be available in one bundle’s classloader but not another’s.
Check for annotation processor issues. Annotation processors (Lombok, MapStruct) generate code at compile time. If the processor version does not match the runtime library version, generated code might reference methods that do not exist.
Check for Java module system (JPMS) restrictions. In Java 9+, the module system can restrict access to methods. Add --add-opens or --add-exports flags if needed.
Check for SLF4J binding conflicts. Multiple SLF4J bindings on the classpath (Logback + Log4j + slf4j-simple) can cause NoSuchMethodError on org.slf4j.Logger.atDebug() and similar fluent API calls. The first binding loaded wins, and if it is an old version, newer methods are missing. Run mvn dependency:tree | grep slf4j and exclude the bindings you do not want.
Check for Lombok or annotation-processor version drift. Lombok 1.18.x generates code that calls JDK APIs at versions matching the build. If your CI uses JDK 17 with Lombok 1.18.20 but production runs JDK 11, generated code may reference methods missing on the runtime JVM. Pin Lombok to a version that supports your runtime JDK and run a smoke test on the produced JAR.
Check Kotlin standard library version. Kotlin code compiled against kotlin-stdlib:1.9.x can call methods that do not exist in kotlin-stdlib:1.8.x. If Spring Boot or another framework pulls in an older Kotlin stdlib via its BOM, your Kotlin code crashes at runtime. Force kotlin-stdlib to the version Kotlin compiled your code with, not the BOM default.
Check shaded JAR ordering on the classpath. When multiple shaded JARs are present, the JVM loads from whichever JAR appears first on the classpath. Run java -verbose:class -jar app.jar 2>&1 | grep GsonBuilder to see which JAR actually loaded the class. The fix is usually to relocate the shaded packages so they cannot collide.
If the class itself is not found (rather than a specific method), see Fix: Java ClassNotFoundException. If the JVM runs out of memory during class loading, see Fix: Java OutOfMemoryError.
For Gradle build failures that prevent the application from running, see Fix: Gradle build failed.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Java Record Not Working — Compact Constructor Error, Serialization Fails, or Cannot Extend
How to fix Java record issues — compact constructor validation, custom accessor methods, Jackson serialization, inheritance restrictions, and when to use records vs regular classes.
Fix: OpenTelemetry Not Working — Traces Not Appearing, Spans Missing, or Exporter Connection Refused
How to fix OpenTelemetry issues — SDK initialization order, auto-instrumentation setup, OTLP exporter configuration, context propagation, and missing spans in Node.js, Python, and Java.
Fix: Spring Boot Test Not Working — ApplicationContext Fails to Load, MockMvc Returns 404, or @MockBean Not Injected
How to fix Spring Boot test issues — @SpringBootTest vs test slices, MockMvc setup, @MockBean vs @Mock, test context caching, and common test configuration mistakes.
Fix: Spring Boot @Cacheable Not Working — Cache Miss Every Time or Stale Data
How to fix Spring Boot @Cacheable issues — @EnableCaching missing, self-invocation bypass, key generation, TTL configuration, cache eviction, and Caffeine vs Redis setup.