junit-team/junit5 · error · UncheckedIOException

Failed to create output dir

Error message

Failed to create output dir

What it means

Thrown as an UncheckedIOException by OutputDir.create() when the underlying createSafely() raises an IOException while resolving or creating the reporting output directory. OutputDir auto-detects the directory as 'target' (when pom.xml exists), 'build' (when a .gradle/.gradle.kts file exists), or the current working directory, unless 'junit.platform.reporting.output.dir' is set. The {uniqueNumber} placeholder is expanded before creation. This is an INTERNAL API (@API status = INTERNAL).

Solutions

  1. Point junit.platform.reporting.output.dir to a known-writable absolute path, e.g. -Djunit.platform.reporting.output.dir=/tmp/junit-output.
  2. Verify write permission on the auto-detected directory (target/ for Maven, build/ for Gradle, or cwd) and chmod/chown it for the JVM user.
  3. Ensure no regular file occupies the intended directory path (Files.createDirectories fails if a file is there).
  4. Free disk space on the volume hosting the output directory.

Example fix

// before
-Djunit.platform.reporting.output.dir=/opt/app/tests/out

// after
-Djunit.platform.reporting.output.dir=/var/tmp/junit-output
Defensive patterns

Strategy: try-catch

Validate before calling

// Preflight: confirm the resolved output directory is creatable & writable.
String custom = System.getProperty("junit.platform.reporting.output.dir");
Path base = (custom == null || custom.isBlank())
        ? Path.of(".").toAbsolutePath()  // OutputDir auto-detects target/build/cwd
        : Path.of(custom).toAbsolutePath();
Path parent = base.getParent() != null ? base.getParent() : base;
if (!Files.isWritable(parent)) {
    throw new IllegalStateException("Output dir parent not writable: " + parent);
}

Try / catch

// OutputDir.create throws UncheckedIOException (it is INTERNAL, so direct use is rare).
try {
    OutputDir outputDir = OutputDir.create(Optional.ofNullable(customDir));
} catch (UncheckedIOException e) {
    // Log the cause IOException and fall back to a guaranteed-writable temp dir.
    Path fallback = Files.createTempDirectory("junit-output");
    outputDir = OutputDir.create(Optional.of(fallback.toString()));
}

Prevention

When it happens

Trigger: Calling OutputDir.create(Optional.of(customDir)) or the no-arg create() when: the resolved directory path is not writable by the JVM user; the path contains illegal filesystem characters; Files.createDirectories() fails because a non-directory file already exists at that path; the parent filesystem is read-only; or the disk is full. The customDir value is resolved against the current working directory and its placeholders are expanded before mkdirs is attempted.

Common situations: Running the JVM as a user without write permission to the project root; pointing junit.platform.reporting.output.dir to a read-only mount or a path inside /opt or /etc; containerized runs where the cwd is an overlay read-only layer; CI agents with a small/full workspace; a file (not a directory) already occupies the target path; the cwd was deleted between build and test phases.

Related errors


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

Appendix: source

Thrown at junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java:46

import org.apiguardian.api.API;
import org.junit.platform.commons.util.StringUtils;

@API(status = INTERNAL, since = "1.9")
public class OutputDir {

	private static final Pattern OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN = Pattern.compile(
		Pattern.quote(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER));

	public static OutputDir create(Optional<String> customDir) {
		return create(customDir, () -> Path.of("."));
	}

	static OutputDir create(Optional<String> customDir, Supplier<Path> currentWorkingDir) {
		try {
			return createSafely(customDir, currentWorkingDir);
		}
		catch (IOException e) {
			throw new UncheckedIOException("Failed to create output dir", e);
		}
	}

	/**
	 * Package private for testing purposes.
	 */
	static OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir) throws IOException {
		return createSafely(customDir, currentWorkingDir, new SecureRandom());
	}

	private static OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir,
			SecureRandom random) throws IOException {
		Path cwd = currentWorkingDir.get().toAbsolutePath();
		Path outputDir;

		if (customDir.isPresent() && StringUtils.isNotBlank(customDir.get())) {
			outputDir = cwd.resolve(expandPlaceholders(customDir.get(), random));
		}

View on GitHub (pinned to f070c699a0)