01
Record the missing class and the surrounding cause
Preserve the full exception chain and identify the class named by the failure. A missing runtime class and a class that previously failed initialization can both appear in a NoClassDefFoundError investigation, so the message and earlier logs matter.
In this reproduction, Main compiled against demo.lib.Message and then ran without the library JAR. The JVM reported NoClassDefFoundError for demo/lib/Message, with ClassNotFoundException in the cause chain. No static-initializer failure was involved.
02
Create a minimal dependency and caller
Save the dependency below as lib/demo/lib/Message.java. It has one public method and no external dependencies. Keeping the reproduction small isolates the difference between compile-time availability and runtime availability.
This fixture is not a replacement for inspecting a real dependency tree. A framework may load application classes from a layout different from this plain classpath example.
package demo.lib;
public class Message {
public static String text() { return "runtime dependency loaded"; }
}03
Compile the caller against the dependency
Save the caller as app/Main.java. Its import and method call require Message during compilation. A successful javac invocation does not automatically copy the dependency into the application output directory.
Package the library using your actual build process in production. The following commands intentionally use a small local JAR rather than downloading or modifying any application dependency.
import demo.lib.Message;
public class Main {
public static void main(String[] args) {
System.out.println(Message.text());
}
}04
Compare the two launch contracts
Run these commands from the reproduction directory after creating the two source files. The first launch intentionally fails. The final launch includes both the compiled app and its dependency and prints runtime dependency loaded.
The colon-separated classpath below is for Linux and macOS; Windows uses a semicolon. With java -jar, ordinary classpath handling differs: inspect the launcher documentation and the application’s packaging instead of assuming this classpath command applies to every executable JAR.
mkdir -p out/lib out/app
javac -d out/lib lib/demo/lib/Message.java
jar --create --file helper.jar -C out/lib .
javac -cp helper.jar -d out/app app/Main.java
# Expected failure: runtime dependency is absent.
java -cp out/app Main
# Corrected plain-classpath launch:
java -cp 'out/app:helper.jar' Main05
Repair packaging and verify the deployed artifact
For the actual application, inspect its built image, distribution, or launch script rather than only the IDE run configuration. Confirm the intended version of the dependency is present and reachable by the relevant loader. Avoid collecting arbitrary JARs from unrelated installations.
Rebuild through the normal pipeline and exercise the exact route that previously triggered loading. Record the artifact identity and runtime command. A successful process start alone can miss a dependency loaded only when a particular feature is used.
Know the limits
Reproduced with Eclipse Temurin OpenJDK 25.0.4.1+1 in a disposable Linux container with no external network. A dependency was available to javac but deliberately omitted when launching the app. Restoring that exact JAR resolved the failure. Custom class loaders, module-path deployments, framework packaging, and remote build dependency resolution were not tested.
Sources & further reading
A technical publication by CoreTrailKit.
Browse all articles