junit-team/junit5 · error · JUnitException

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

Error message

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

What it means

Thrown by the FileSource constructor (line 71-80) when file.getCanonicalFile() raises IOException, wrapped in a JUnitException. FileSource.from(File) attaches a file as a TestSource. Like DirectorySource, no existence check is performed here.

Source

Thrown at junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java:77

	public static FileSource from(File file, @Nullable FilePosition filePosition) {
		return new FileSource(file, filePosition);
	}

	private final File file;

	private final @Nullable FilePosition filePosition;

	private FileSource(File file) {
		this(file, null);
	}

	private FileSource(File file, @Nullable FilePosition filePosition) {
		Preconditions.notNull(file, "file must not be null");
		try {
			this.file = file.getCanonicalFile();
		}
		catch (IOException ex) {
			throw new JUnitException("Failed to retrieve canonical path for file: " + file, ex);
		}
		this.filePosition = filePosition;
	}

	private FileSource(FileSource fileSource, @Nullable FilePosition filePosition) {
		this.file = fileSource.file;
		this.filePosition = filePosition;
	}

	/**
	 * Get the {@link URI} for the source {@linkplain #getFile file}.
	 *
	 * @return the source {@code URI}; never {@code null}
	 */
	@Override
	public URI getUri() {
		return getFile().toURI();
	}

View on GitHub (pinned to 956246301e)

Solutions

  1. Pre-canonicalize with Path.toRealPath().toFile() and pass the resolved File to FileSource.from(...).
  2. Guard with Files.isRegularFile(Path) before constructing.
  3. Use the withPosition(FilePosition) method on an existing FileSource to add positions, avoiding repeated canonical resolution (per its javadoc at line 130).
  4. Inspect the caused-by IOException for the root filesystem fault.

Example fix

// before
TestSource source = FileSource.from(new File(filePath), FilePosition.from(42).orElse(null));

// after
File canonical = Path.of(filePath).toRealPath().toFile();
TestSource source = FileSource.from(canonical, FilePosition.from(42).orElse(null));
Defensive patterns

Strategy: validation

Validate before calling

File canonical = Path.of(filePath).toRealPath().toFile();
TestSource source = FileSource.from(canonical, position);

Try / catch

try {
    return FileSource.from(file);
} catch (JUnitException e) {
    throw new IllegalStateException("cannot build FileSource for " + file, e.getCause());
}

Prevention

When it happens

Trigger: Calling FileSource.from(file) (or FileSource.from(file, position)) for a file whose canonical path cannot be resolved (broken symlink, missing parent directory, filesystem I/O error, unreachable mount).

Common situations: Custom engine/extension building a file-backed TestSource for a stale or broken path; test descriptors cached across filesystem changes; CI on ephemeral filesystems; symlinks pointing to deleted originals.

Related errors


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