junit-team/junit5 · error · UncheckedIOException

Failed to copy files to the output directory

Error message

Failed to copy files to the output directory

What it means

Thrown as UncheckedIOException inside TestReporter.publishDirectory(Path) when copying a file from the source directory tree to the report output directory fails with an IOException (Files.copy or Files.createDirectories inside the Files.walk loop). It wraps the underlying I/O error so the test fails loudly rather than silently producing a partial directory.

Source

Thrown at junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java:160

	@API(status = MAINTAINED, since = "5.13.3")
	default void publishDirectory(Path directory) {
		Preconditions.notNull(directory, "directory must not be null");
		Preconditions.condition(Files.exists(directory), () -> "directory must exist: " + directory);
		Preconditions.condition(Files.isDirectory(directory), () -> "path must represent a directory: " + directory);
		publishDirectory(directory.getFileName().toString(), path -> {
			try (Stream<Path> stream = Files.walk(directory)) {
				stream.forEach(source -> {
					Path destination = path.resolve(directory.relativize(source));
					try {
						if (Files.isDirectory(source)) {
							Files.createDirectories(destination);
						}
						else {
							Files.copy(source, destination, REPLACE_EXISTING);
						}
					}
					catch (IOException e) {
						throw new UncheckedIOException("Failed to copy files to the output directory", e);
					}
				});
			}
		});
	}

	/**
	 * Publish a file with the supplied name and media type written by the supplied
	 * action and attach it to the current test or container.
	 *
	 * <p>The {@link Path} passed to the supplied action will be relative to the
	 * report output directory, but it is up to the action to write the file.
	 *
	 * @param name the name of the file to be published; never {@code null} or
	 * blank and must not contain any path separators
	 * @param mediaType the media type of the file; never {@code null}; use
	 * {@link org.junit.jupiter.api.extension.MediaType#APPLICATION_OCTET_STREAM}
	 * if unknown

View on GitHub (pinned to 956246301e)

Solutions

  1. Verify the report output directory is writable and has enough free space before publishing.
  2. Ensure the source directory is stable (no concurrent mutation) during publishDirectory.
  3. Use unique directory/file names per test (e.g., prefixed with the test display name) to avoid parallel write collisions.
  4. If the wrapped IOException is transient (e.g., short disk hiccup), re-run the test on a healthy worker.

Example fix

// before
testReporter.publishDirectory(Path.of("build/output")); // fails if build/output not writable

// after — preflight the source and ensure the output root is writable
Path src = Path.of("build/output");
if (!Files.isReadable(src) || !Files.isDirectory(src)) {
    throw new IllegalStateException("source dir missing: " + src);
}
testReporter.publishDirectory(src);
Defensive patterns

Strategy: try-catch

Validate before calling

Path src = /* directory to publish */;
if (!Files.isDirectory(src) || !Files.isReadable(src)) {
    throw new IllegalStateException("source directory not readable: " + src);
}
// best-effort stability check: snapshot the entry list
long count;
try (var s = Files.walk(src)) { count = s.count(); }
// ensure report output root is writable by publishing a tiny probe first if unsure

Try / catch

try {
    testReporter.publishDirectory(src);
} catch (java.io.UncheckedIOException e) {
    // log and fall back to publishing individual files, or mark the test as incomplete
    System.err.println("publishDirectory failed: " + e.getCause());
    throw e;
}

Prevention

When it happens

Trigger: Calling testReporter.publishDirectory(dirPath) where dirPath is readable but the report output directory is not writable, a source file is deleted/made unreadable during the walk, the output filesystem is full, or a destination path cannot be created (e.g., a name collision with an existing file where a directory is expected).

Common situations: Tests that publish generated artifacts (screenshots, coverage dumps, HTML reports) to a report dir; CI sandboxes where the output root is read-only or ephemeral; parallel tests racing on the same output filename.

Related errors


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