junit-team/junit5 · error · JUnitException

Failed to create output directory

Error message

Failed to create output directory

What it means

Thrown by AbstractExtensionContext.createOutputDirectory() when the JupiterConfiguration's OutputDirectoryCreator.createOutputDirectory(testDescriptor) raises an IOException. The output directory is the parent location into which publishFile/publishDirectory resolve file names, so its creation is a precondition for any file-publishing API.

Source

Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java:197

			() -> "name must not contain path separators: " + name);
		try {
			action.accept(path);
		}
		catch (Throwable t) {
			UnrecoverableExceptions.rethrowIfUnrecoverable(t);
			throw new JUnitException("Failed to publish path", t);
		}
		Preconditions.condition(Files.exists(path), () -> "Published path must exist: " + path);
		FileEntry fileEntry = fileEntryCreator.apply(path);
		this.engineExecutionListener.fileEntryPublished(this.testDescriptor, fileEntry);
	}

	private Path createOutputDirectory() {
		try {
			return configuration.getOutputDirectoryCreator().createOutputDirectory(this.testDescriptor);
		}
		catch (IOException e) {
			throw new JUnitException("Failed to create output directory", e);
		}
	}

	@Override
	public Optional<ExtensionContext> getParent() {
		return Optional.ofNullable(this.parent);
	}

	@Override
	public ExtensionContext getRoot() {
		if (this.parent != null) {
			return this.parent.getRoot();
		}
		return this;
	}

	protected T getTestDescriptor() {
		return this.testDescriptor;

View on GitHub (pinned to 956246301e)

Solutions

  1. Check the cause IOException for the exact path and OS error (permission denied, no such file, read-only file system).
  2. Ensure the base output directory configured for the launcher is writable by the test JVM user.
  3. If using a custom OutputDirectoryCreator, make it create missing parent directories (Files.createDirectories) and fall back to a sane default.
  4. Set/verify the relevant configuration parameter that determines the output location before launching the test plan.

Example fix

// before — creator returns a path under a read-only root
LauncherDiscoveryRequestBuilder.request()
    .configurationParameter("junit.jupiter.output.directory", "/opt/read-only/reports")
    .build();
// after
LauncherDiscoveryRequestBuilder.request()
    .configurationParameter("junit.jupiter.output.directory", System.getProperty("java.io.tmpdir") + "/junit-reports")
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// Validate the output directory creator base before launch
Path base = Paths.get(System.getProperty("junit.jupiter.output.dir", "build/junit-output"));
try { Files.createDirectories(base); } catch (IOException e) { throw new IllegalStateException(e); }
if (!Files.isWritable(base)) throw new IllegalStateException("Not writable: " + base);

Prevention

When it happens

Trigger: Calling ExtensionContext.publishFile(...) or publishDirectory(...) when the configured OutputDirectoryCreator cannot create the directory — e.g. the derived path is rooted at a read-only location, the parent does not exist and cannot be created, or a security manager denies access.

Common situations: A custom OutputDirectoryCreator registered via LauncherDiscoveryRequestBuilder that computes a path from the test descriptor pointing into a non-writable area; running tests as a user without write permission to the configured base; container/CI environments with a read-only workspace; a creator that relies on a system property (junit.platform.output.*) that was not set, defaulting to an invalid root.

Related errors


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