Skip to content
Latchkey

Java "java.lang.ClassNotFoundException" at Runtime - Fix Classpath in CI

The JVM tried to load a class by name at runtime and could not find its .class file anywhere on the classpath. It compiled because the type was visible then, but the artifact that contains it is absent when the program actually runs.

What this error means

A run or test throws java.lang.ClassNotFoundException: com.example.Foo, usually from Class.forName, a service loader, or a reflective lookup. Compilation passed; the failure only appears when the class is loaded.

java
Exception in thread "main" java.lang.ClassNotFoundException: com.example.driver.PgDriver
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at com.example.App.main(App.java:18)

Common causes

A runtime dependency is missing from the classpath

A library used only via reflection (JDBC drivers, SPI providers) is declared provided/compileOnly, or not declared at all, so it is not present when the JVM resolves the name.

A fat jar or test classpath dropped the class

A shaded/assembly build excluded the package, or the test runtime classpath differs from compile, so the loader has no .class for that name.

How to fix it

Declare the dependency with runtime scope

Add the artifact that contains the class so it ships on the runtime classpath, not just at compile time.

pom.xml
<!-- Maven: runtime so the driver is on the run/test classpath -->
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.7.3</version>
  <scope>runtime</scope>
</dependency>

Inspect what is actually on the classpath

  1. Run mvn dependency:tree (or gradle dependencies) and confirm the artifact appears in the runtime/test configuration.
  2. For a fat jar, list its contents (jar tf app.jar | grep Foo) to verify the class was packaged.
  3. Check that the class is not declared provided or compileOnly when it is needed at runtime.

How to prevent it

  • Use runtime scope for reflection-only libraries (JDBC, SPI), and assert the packaged jar contains required classes in CI before publishing.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →