junit-team/junit5 · error · JUnitException

Invalid classpath entry

Error message

Invalid classpath entry: ${path}

What it means

ConsoleTestExecutor.toURL() converts a user-supplied --additional-classpath-entry path into a URL for a custom URLClassLoader. If the Path cannot be turned into a URI/URL (typically an IOException or malformed input), a JUnitException wraps the cause. It signals the entry supplied on the command line cannot be used as a classpath root.

Solutions

  1. Verify the path exists and is on the default/platform FileSystem: Files.exists(path) && path.getFileSystem() == FileSystems.getDefault().
  2. Convert the entry to a real file on disk (extract or copy) and reference that absolute path.
  3. If the path is valid but special-character-laden, URL-encode the path or use the file:// URI form directly if supported by the surrounding setup.
  4. Prefer putting the jar/directory on the real -cp / CLASSPATH instead of --additional-classpath-entry when in doubt.

Example fix

// before
java -jar junit-platform-console-standalone.jar execute --additional-classpath-entry /opt/missing/lib.jar
// after: ensure the path exists and is a real file
ls /opt/missing/lib.jar  # fix path
java -jar junit-platform-console-standalone.jar execute --additional-classpath-entry /opt/real/lib.jar
Defensive patterns

Strategy: validation

Validate before calling

// Validate the path before passing it as an additional classpath entry.
import java.nio.file.*;
Path p = Paths.get(userEntry);
if (!Files.exists(p))      throw new IllegalArgumentException("classpath entry does not exist: " + userEntry);
if (!Files.isReadable(p))  throw new IllegalArgumentException("classpath entry not readable: " + userEntry);
if (p.getFileSystem() != FileSystems.getDefault())
  throw new IllegalArgumentException("classpath entry is not on the default filesystem: " + userEntry);
// If ok, pass --additional-classpath-entry userEntry

Prevention

When it happens

Trigger: Passing --additional-classpath-entry with a path that does not exist or whose Path.toUri().toURL() throws — e.g. a path on a non-default FileSystem (a Path inside a zip/jar via a custom provider), a path with characters the URI parser rejects, or a path whose provider does not support URL conversion.

Common situations: Pointing --additional-classpath-entry at a non-existent file, a directory inside a custom FileSystem (e.g. a Path obtained from an opened jar FileSystem), or a path with unencoded special characters. Also seen when the supplied string resolves against an unusual default FileSystem.

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/f9e1b1321470dca0. Report an issue: GitHub.

Appendix: source

Thrown at junit-platform-console/src/main/java/org/junit/platform/console/command/ConsoleTestExecutor.java:183

		launcher.execute(executionRequest);
	}

	private @Nullable CustomClassLoader createCustomClassLoader() {
		List<Path> additionalClasspathEntries = discoveryOptions.getExistingAdditionalClasspathEntries();
		if (!additionalClasspathEntries.isEmpty()) {
			URL[] urls = additionalClasspathEntries.stream().map(this::toURL).toArray(URL[]::new);
			ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader();
			return new CustomClassLoader(URLClassLoader.newInstance(urls, parentClassLoader));
		}
		return null;
	}

	private URL toURL(Path path) {
		try {
			return path.toUri().toURL();
		}
		catch (Exception ex) {
			throw new JUnitException("Invalid classpath entry: " + path, ex);
		}
	}

	private SummaryGeneratingListener registerListeners(PrintWriter out, Optional<Path> reportsDir, Launcher launcher,
			@Nullable CancellationToken cancellationToken) {

		// always register summary generating listener
		SummaryGeneratingListener summaryListener = new SummaryGeneratingListener();
		launcher.registerTestExecutionListeners(summaryListener);
		// optionally, register test plan execution details printing listener
		createDetailsPrintingListener(out).ifPresent(launcher::registerTestExecutionListeners);
		// optionally, register XML reports writing listener
		createXmlWritingListener(out, reportsDir).ifPresent(launcher::registerTestExecutionListeners);
		createFailFastListener(cancellationToken).ifPresent(launcher::registerTestExecutionListeners);
		return summaryListener;
	}

	private Optional<DetailsPrintingListener> createDetailsPrintingListener(PrintWriter out) {

View on GitHub (pinned to f070c699a0)