javaseverity: critical
ClassNotFoundException

Java ClassNotFoundException — Class not found on the classpath at runtime

ClassNotFoundException: cannot find class at runtime

95% fixable~15 mindifficulty: intermediate

Verified against OpenJDK 21 documentation, JLS §12.2, Maven Dependency Plugin docs · Updated June 2026

> quick_fix

Add the missing JAR to your build tool dependency (Maven/Gradle) or verify the classpath includes the directory or JAR that contains the class named in the exception message.

<!-- Maven: add missing dependency -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>missing-library</artifactId>
    <version>1.0.0</version>
</dependency>

<!-- Gradle: -->
// implementation 'com.example:missing-library:1.0.0'

What causes this error

ClassNotFoundException is thrown by the ClassLoader when it cannot find a class with the specified fully-qualified name on the current classpath. It typically surfaces when calling Class.forName(), ClassLoader.loadClass(), or a JDBC driver registration like Class.forName("com.mysql.cj.jdbc.Driver").

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Read the full class name from the exception

    The exception message contains the exact fully-qualified class name that could not be found, e.g., `com.mysql.cj.jdbc.Driver`. Use this to identify the missing library.

  2. 02

    step 2

    Add the missing dependency to your build tool

    Search Maven Central for the artifact containing the class. For JDBC drivers: MySQL = `mysql:mysql-connector-java`, PostgreSQL = `org.postgresql:postgresql`. Add it to pom.xml or build.gradle and re-run the build.

  3. 03

    step 3

    Verify scope is not test-only or provided

    In Maven, a dependency with `<scope>provided</scope>` or `<scope>test</scope>` will not be included in the packaged JAR/WAR. Change to `compile` (the default) if the class is needed at runtime.

  4. 04

    step 4

    Check fat-JAR / shade plugin configuration

    If you build an executable JAR with maven-shade-plugin or Gradle's shadow plugin, ensure the dependency is not excluded from the merged artifact. List the JAR contents with `jar tf app.jar | grep ClassName` to confirm.

  5. 05

    step 5

    Distinguish from NoClassDefFoundError

    ClassNotFoundException means the class was never on the classpath. NoClassDefFoundError means the class was present at compile time but missing at runtime (often a transitive dependency). Different causes, different fixes.

How to verify the fix

  • Run `mvn dependency:tree` or `gradle dependencies` to confirm the JAR is resolved
  • List JAR contents and confirm the class file is present: `jar tf app.jar | grep DriverClass`
  • Run the application — the ClassNotFoundException should not recur

Why ClassNotFoundException happens at the runtime level

The Java ClassLoader searches for classes by traversing the classpath — a list of directories and JAR files — looking for a `.class` file matching the fully-qualified class name. When Class.forName() is called and the ClassLoader exhausts all entries without finding the class, it throws ClassNotFoundException. This is distinct from compile-time resolution: a class can exist at compile time (e.g., provided by the IDE or a provided-scope dependency) but be absent from the runtime classpath of a packaged artifact.

Common debug mistakes for ClassNotFoundException

  • Using `<scope>provided</scope>` for a JDBC driver or other runtime dependency in Maven
  • Forgetting to include the dependency in a fat-JAR build (maven-shade-plugin mergeStrategy exclusions)
  • Copy-pasting Class.forName() driver registration with an outdated class name (e.g., old MySQL driver was `com.mysql.jdbc.Driver`, new is `com.mysql.cj.jdbc.Driver`)
  • Deploying to a container that uses a different JDK/JRE than the development machine, missing optional JDK modules

When ClassNotFoundException signals a deeper problem

ClassNotFoundException at runtime exposes a fundamental gap in Java's build-time safety: the compiler does not validate that all classes referenced via string literals in Class.forName() actually exist. This makes JDBC driver loading and reflection-heavy frameworks (Spring XML config, legacy Hibernate) brittle — a typo in a string or a missing JAR line in a deploy script surfaces only after deployment. Modern Spring Boot auto-configuration and JDBC URL-based driver detection largely eliminate explicit Class.forName() calls, reducing this failure mode significantly.

Editor's take

ClassNotFoundException is almost always a packaging problem, not a code problem. The class exists — you can see it in your IDE — but it did not make it into the deployed artifact. The fastest diagnostic is `jar tf your-app.jar | grep <ClassName>` on the production artifact, not on your local IDE classpath. In Spring Boot projects, this surfaces most often when developers add a dependency to the parent POM with provided scope and then deploy the child module standalone. Get into the habit of testing the packaged artifact locally with `java -jar` before deploying, not just running from the IDE.

The trickiest variant I've seen is ClassNotFoundException inside application servers like Tomcat or WildFly, where class loader isolation means a JAR in one WAR file cannot see classes in another WAR file — even though both are deployed on the same server. Developers spend hours checking their POM when the actual fix is moving the shared JAR into the server's lib directory or restructuring into an EAR with a shared library module. If the exception only fires when two WARs interact, class loader boundaries are your first suspect.

Another pattern that catches teams off guard: ClassNotFoundException after upgrading Java versions. Between Java 8 and Java 11, several packages were removed from the JDK entirely — javax.xml.bind (JAXB), javax.activation, and the CORBA stack. Code that compiled fine on Java 8 throws ClassNotFoundException on Java 11+ because these classes no longer ship with the JDK. The fix is adding explicit Maven dependencies for the removed modules (jakarta.xml.bind-api for JAXB, jakarta.activation-api for activation). This is a one-time migration cost, but it surprises every team that upgrades without reading the JDK migration guide first.

By Bikram Nath · Curator · Updated June 2026

Frequently asked questions

What is the difference between ClassNotFoundException and NoClassDefFoundError?

ClassNotFoundException is a checked exception thrown when you explicitly try to load a class by name (e.g., Class.forName()) and it is not on the classpath. NoClassDefFoundError is an error thrown by the JVM when a class that was available at compile time cannot be found at runtime — often caused by a missing transitive dependency in a packaged artifact.

Why do I get ClassNotFoundException only in production, not locally?

Your local IDE adds all project dependencies to the classpath automatically. In production, only what is packaged inside the JAR/WAR is available. A dependency with test or provided scope, or one accidentally excluded from the shade/assembly plugin, will be missing in the deployed artifact.

Can ClassNotFoundException be caused by a class loader isolation issue?

Yes. In application servers (Tomcat, JBoss) or OSGi containers, each module has its own class loader. A class visible to one module may not be visible to another. Check the container's class loading delegation order and ensure the JAR is in the correct lib directory.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.