junit-team/junit5 · error · PreconditionViolationException

Failed to retrieve canonical path for directory: ${directory

Error message

Failed to retrieve canonical path for directory: ${directory}

What it means

Thrown by DiscoverySelectors.selectDirectory(File) at line 221-232 when directory.getCanonicalPath() raises IOException. The isDirectory() precondition (line 223) passes first, so this fires only when an existing directory's canonical path cannot be computed.

Source

Thrown at junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java:229

	 * <p>This method selects the directory in its {@linkplain File#getCanonicalPath()
	 * canonical} form and throws a {@link PreconditionViolationException} if the
	 * directory does not exist.
	 *
	 * @param directory the directory to select; never {@code null}
	 * @see DirectorySelector
	 * @see #selectDirectory(String)
	 * @see #selectFile(String)
	 * @see #selectFile(File)
	 */
	public static DirectorySelector selectDirectory(File directory) {
		Preconditions.notNull(directory, "Directory must not be null");
		Preconditions.condition(directory.isDirectory(),
			() -> "The supplied java.io.File [%s] must represent an existing directory".formatted(directory));
		try {
			return new DirectorySelector(directory.getCanonicalPath());
		}
		catch (IOException ex) {
			throw new PreconditionViolationException("Failed to retrieve canonical path for directory: " + directory,
				ex);
		}
	}

	/**
	 * Create a list of {@code ClasspathRootSelectors} for the supplied
	 * <em>classpath roots</em> (directories or JAR files).
	 *
	 * <p>Since the supplied paths are converted to {@link URI URIs}, the
	 * {@link java.nio.file.FileSystem} that created them must be the
	 * {@linkplain java.nio.file.FileSystems#getDefault() default} or one that
	 * has been created by an installed
	 * {@link java.nio.file.spi.FileSystemProvider}.
	 *
	 * <p>Since {@linkplain org.junit.platform.engine.TestEngine engines} are not
	 * expected to modify the classpath, the classpath roots represented by the
	 * resulting selectors must be on the classpath of the
	 * {@linkplain Thread#getContextClassLoader() context class loader} of the

View on GitHub (pinned to 956246301e)

Solutions

  1. Pre-resolve the canonical path with Path.toRealPath() and pass the resulting absolute path string to selectDirectory(String) which does not re-resolve.
  2. Verify Files.isReadable(dir) and that the parent chain is intact before selection.
  3. Replace directory symlinks with their real targets in test configuration.
  4. Inspect the caused-by IOException for the precise filesystem error.

Example fix

// before
var selector = DiscoverySelectors.selectDirectory(new File(dirPath));

// after
String canonical = Path.of(dirPath).toRealPath().toString();
var selector = DiscoverySelectors.selectDirectory(canonical); // String overload stores as-is
Defensive patterns

Strategy: validation

Validate before calling

File d = new File(dirPath);
if (!d.isDirectory()) throw new IllegalArgumentException("not a directory: " + d);
String canonical = Path.of(dirPath).toRealPath().toString();
var selector = DiscoverySelectors.selectDirectory(canonical);

Try / catch

try {
    return DiscoverySelectors.selectDirectory(dir);
} catch (PreconditionViolationException e) {
    throw new IllegalStateException("cannot canonicalize dir: " + dir, e.getCause());
}

Prevention

When it happens

Trigger: Calling selectDirectory(dir) where 'dir' is a real directory but canonical resolution fails (broken parent symlink, I/O error on the filesystem, network filesystem dropped mid-operation, or OS-level path-length limits).

Common situations: Directories reached via dangling symlinks in the parent chain; selecting directories on transient mounts (Docker volumes, removable media); running under restricted security managers; CI runners with unusual filesystem layouts.

Related errors


AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04). Data as JSON: /data/errors/ed68793ffd9b7469.json. Report an issue: GitHub.