junit-team/junit5 · warning · JUnitException
Failed to close custom class loader
Error message
Failed to close custom class loader
What it means
CustomClassLoaderCloseStrategy.CLOSE_AFTER_CALLING_LAUNCHER.handle() closes the custom URLClassLoader that the console launcher created to load user classes. If close() throws, a JUnitException wraps it. This is a cleanup-time failure after discovery/execution has completed.
Solutions
- Switch to the KEEP_OPEN close strategy (the launcher then relies on JVM/System.exit to release resources) — pass the corresponding option/property to keep the classloader open.
- Ensure no external code holds or closes the custom classloader; ensure the jar/directory is not locked (close other processes holding it, especially on Windows).
- Move the classpath root to local disk to avoid network-mounted I/O failures during close.
- Verify junit-platform-console and junit-platform-launcher versions are aligned so the close strategy is the expected one.
Example fix
// before: default CLOSE_AFTER_CALLING_LAUNCHER triggers close() java -jar junit-platform-console-standalone.jar execute --additional-classpath-entry /mnt/nfs/lib.jar // after: keep the loader open and rely on JVM teardown java -jar junit-platform-console-standalone.jar execute --additional-classpath-entry /mnt/nfs/lib.jar --disable-banner=false # use the keep-open option per current CLI help
Defensive patterns
Strategy: fallback
Try / catch
// Close-strategy failures happen at teardown; wrap launcher invocation if you drive it programmatically.
try {
launcher.execute(request);
} catch (org.junit.platform.commons.JUnitException e) {
if (e.getMessage() != null && e.getMessage().contains("Failed to close custom class loader")) {
// tests already ran; log and continue, or switch to keep-open strategy
log.warn("Custom classloader close failed; results may still be valid.", e);
} else throw e;
} Prevention
- Run with the keep-open close strategy when you call System.exit afterward (e.g. the standalone jar does this).
- Avoid network-mounted jars as additional classpath entries to dodge I/O failures on close.
- On Windows, ensure no process holds an exclusive lock on the jar before the run.
When it happens
Trigger: After the Launcher finishes, the console launcher closes its internally created URLClassLoader; an exception (e.g. an I/O error closing a jar resource, or a classloader already closed) bubbles up as this error. The default strategy is to close after calling the launcher; KEEP_OPEN avoids it but requires System.exit.
Common situations: Running tests against a directory/jar on a network mount or a non-default FileSystem where closing resources fails; an externally held reference to the classloader closing it first; or a jar that is locked on Windows. The test run itself usually succeeded — only the teardown fails.
Related errors
- Could not open color palette properties file
- Error redirecting stderr to file
- Error redirecting stdout and stderr to file
- Error redirecting stdout to file
- Invalid classpath entry
AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11).
Data as JSON: /api/errors/aefe55cef64d1fbf.
Report an issue: GitHub.
Appendix: source
Thrown at junit-platform-console/src/main/java/org/junit/platform/console/command/CustomClassLoaderCloseStrategy.java:38
* discovery and execution.
*/
@API(status = INTERNAL, since = "1.13")
public enum CustomClassLoaderCloseStrategy {
/**
* Close the custom class loader after calling the
* {@link org.junit.platform.launcher.Launcher} for test discovery or
* execution.
*/
CLOSE_AFTER_CALLING_LAUNCHER {
@Override
void handle(CustomClassLoader customClassLoader) {
try {
customClassLoader.close();
}
catch (Exception ex) {
throw new JUnitException("Failed to close custom class loader", ex);
}
}
},
/**
* Rely on the JVM to release resources held by the custom class loader when
* it terminates.
*
* <p>This mode is only safe to use when calling {@link System#exit(int)}
* afterward.
*/
KEEP_OPEN {
@Override
void handle(CustomClassLoader customClassLoader) {
// do nothing
}
};View on GitHub (pinned to f070c699a0)