junit-team/junit5 · error · JUnitException

Failed to publish path

Error message

Failed to publish path

What it means

Thrown by AbstractExtensionContext.publishFileEntry when the ThrowingConsumer<Path> action that writes a published file entry (e.g. a @Write wrapper or ExtensionContext.publishFile call) raises any Throwable. The action is invoked against a path resolved inside the per-test output directory; any failure (disk full, permission denied, IO error) is wrapped into a JUnitException with the cause attached rather than being swallowed.

Solutions

  1. Check the attached cause (getCause()) for the real IOException and address that: free disk space, fix permissions on the output directory, or remove the read-only mount.
  2. Verify the output directory creator returns a writable location via the junit.platform.output.dir configuration or JupiterConfiguration outputDirectoryCreator.
  3. Ensure the published file name passed to publishFile does not itself trigger an IOException in your writer lambda (e.g. close streams before returning).

Example fix

// before
context.publishFile("report.txt", path -> {
    Files.writeString(path, payload); // throws if disk full / read-only
});
// after - ensure target dir is writable before publishing
Path outDir = context.getConfigurationDirectory();
if (!Files.isWritable(outDir)) throw new IllegalStateException("output dir not writable: " + outDir);
context.publishFile("report.txt", path -> Files.writeString(path, payload));
Defensive patterns

Strategy: try-catch

Validate before calling

Path outDir = context.getConfigurationDirectory(); // or however you obtain it
if (outDir == null || !Files.isWritable(outDir)) {
    throw new IllegalStateException("Output dir not writable: " + outDir);
}
context.publishFile("report.txt", path -> Files.writeString(path, payload));

Try / catch

try {
    context.publishFile("report.txt", path -> Files.writeString(path, payload));
} catch (JUnitException e) {
    Throwable cause = e.getCause();
    log.error("publish failed due to: {}", cause == null ? e : cause);
    throw e;
}

Prevention

When it happens

Trigger: Calling ExtensionContext.publishFile(String, ThrowingConsumer) or publishFileAsHex where the consumer lambda throws an IOException, RuntimeException, or other error while writing to the resolved Path. The throw site is action.accept(path) inside publishFileEntry.

Common situations: Test directory not writable (CI sandbox / read-only mount), out of disk space, a nested path separator slipped past the precondition (very rare), or a custom extension that overrides publishing and writes more bytes than the filesystem accepts.

Related errors


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

Appendix: source

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

		};
		publishFileEntry(name, enhancedAction, path -> {
			Preconditions.condition(Files.isDirectory(path), () -> "Published path must be a directory: " + path);
			return FileEntry.from(path, null);
		});
	}

	private void publishFileEntry(String name, ThrowingConsumer<Path> action,
			Function<Path, FileEntry> fileEntryCreator) {
		Path dir = createOutputDirectory();
		Path path = dir.resolve(name);
		Preconditions.condition(path.getParent() != null && path.getParent().equals(dir),
			() -> "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);

View on GitHub (pinned to f070c699a0)