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
- 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.
- Verify the output directory creator returns a writable location via the junit.platform.output.dir configuration or JupiterConfiguration outputDirectoryCreator.
- 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
- Verify the configured output directory is writable before publishing.
- Catch JUnitException only at the test orchestration layer and inspect getCause() for the real IOException.
- Keep publish lambdas small so the failure is attributable to a single IO operation.
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
- Error redirecting stderr to file
- Error redirecting stdout and stderr to file
- Error redirecting stdout to file
- Failed to copy files to the output directory
- Failed to create default temp directory
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)