Java "InvocationTargetException" in CI - Find the Wrapped Cause
InvocationTargetException is a wrapper: a method called via reflection (frameworks, launchers, JUnit, plugin runners) threw, and reflection rethrows it boxed. The interesting failure is the cause it wraps, not the wrapper.
What this error means
A run or test fails with Caused by: java.lang.reflect.InvocationTargetException and a further Caused by: underneath (an NPE, an IllegalState, a config error). It is common from main launchers, Spring, and Gradle/Maven plugin execution.
Caused by: java.lang.reflect.InvocationTargetException
at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(...)
at org.example.Launcher.run(Launcher.java:42)
Caused by: java.lang.IllegalStateException: connection pool not initialized
at com.example.Db.connect(Db.java:31)Common causes
The invoked code threw an exception
Reflection cannot let an arbitrary checked/unchecked exception propagate, so it wraps it. The wrapper hides the true error until you read one level deeper.
A framework entry point failed
App launchers, plugin runners, and DI containers invoke your code reflectively; any failure inside surfaces as InvocationTargetException at the boundary.
How to fix it
Read past the wrapper to the real Caused by
- Scroll to the deepest
Caused by:below the InvocationTargetException - that line is the real failure. - Fix that root cause (missing config, NPE, bad state); the wrapper disappears once it is resolved.
- If logs truncate the cause, increase the framework log level to print the full chain.
Surface the cause in your own reflective calls
When you invoke reflectively, unwrap the target exception so logs show the real error.
try {
method.invoke(target, args);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause()); // surface the real failure
}How to prevent it
- Always inspect the nested
Caused by, and unwrap target exceptions in your own reflection code so the underlying error is never hidden.