Skip to content

Fix: Java NoSuchMethodError

FixDevs · (Updated: )

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;)Z
java.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 run mvn dependency:tree or ./gradlew dependencies against 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-plugin with DependencyConvergence, Gradle failOnVersionConflict()). 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.jar with --server.port=0 and 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:tree

Look 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 runtimeClasspath

Find 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:class JVM 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 package

Gradle:

./gradlew clean build

IntelliJ 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 package without clean after changing dependency versions. Maven’s incremental compilation does not always recompile classes affected by dependency changes. Always use mvn clean package when 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 -version

Fix: 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=test

Compare 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.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles