Java ClassNotFoundException — Class not found on the classpath at runtime
ClassNotFoundException: cannot find class at runtime
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").
How to fix it
- 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.
- 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.
- 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.
- 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.
- 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.