{"id":"abe6e1a3211ec843","repo":"junit-team/junit5","slug":"failed-to-publish-path","errorCode":null,"errorMessage":"Failed to publish path","messagePattern":"Failed to publish path","errorType":"exception","errorClass":"JUnitException","httpStatus":null,"severity":"error","filePath":"junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java","lineNumber":185,"sourceCode":"\t\t};\n\t\tpublishFileEntry(name, enhancedAction, path -> {\n\t\t\tPreconditions.condition(Files.isDirectory(path), () -> \"Published path must be a directory: \" + path);\n\t\t\treturn FileEntry.from(path, null);\n\t\t});\n\t}\n\n\tprivate void publishFileEntry(String name, ThrowingConsumer<Path> action,\n\t\t\tFunction<Path, FileEntry> fileEntryCreator) {\n\t\tPath dir = createOutputDirectory();\n\t\tPath path = dir.resolve(name);\n\t\tPreconditions.condition(path.getParent() != null && path.getParent().equals(dir),\n\t\t\t() -> \"name must not contain path separators: \" + name);\n\t\ttry {\n\t\t\taction.accept(path);\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\tUnrecoverableExceptions.rethrowIfUnrecoverable(t);\n\t\t\tthrow new JUnitException(\"Failed to publish path\", t);\n\t\t}\n\t\tPreconditions.condition(Files.exists(path), () -> \"Published path must exist: \" + path);\n\t\tFileEntry fileEntry = fileEntryCreator.apply(path);\n\t\tthis.engineExecutionListener.fileEntryPublished(this.testDescriptor, fileEntry);\n\t}\n\n\tprivate Path createOutputDirectory() {\n\t\ttry {\n\t\t\treturn configuration.getOutputDirectoryCreator().createOutputDirectory(this.testDescriptor);\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new JUnitException(\"Failed to create output directory\", e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Optional<ExtensionContext> getParent() {\n\t\treturn Optional.ofNullable(this.parent);","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/AbstractExtensionContext.java#L167-L203","documentation":"Thrown by AbstractExtensionContext.publishFileEntry() when the ThrowingConsumer<Path> action passed to ExtensionContext.publishFile() or publishDirectory() throws while writing to the resolved path. The engine catches the Throwable, rethrows unrecoverable exceptions, and wraps the rest in a JUnitException so the failure is attributable to the file-publishing step rather than the user's arbitrary exception type.","triggerScenarios":"Calling ExtensionContext.publishFile(name, mediaType, action) or publishDirectory(name, action) where the action lambda throws an IOException, RuntimeException, or Error while writing to the supplied Path. Also fires if the action runs but a later Files.exists check inside the action's own writes fails due to the action rethrowing.","commonSituations":"Extensions that publish reports/screenshots/artifacts via publishFile and write to a path on a full or read-only disk, an action that opens a stream and forgets to handle a broken pipe, or an action whose content-generation logic throws (e.g. serialization failure). Also when the configured output directory is on a network mount that drops mid-write.","solutions":["Inspect the cause (getCause()) of the JUnitException — it is the original throwable from your action and pinpoints the failing I/O or logic step.","Ensure your publishFile/publishDirectory action performs all writes to the supplied Path and closes all streams in a try-with-resources before returning.","Verify the output directory is writable and has free space; the path is created by the configured OutputDirectoryCreator.","Catch expected business exceptions inside your action and either recover or rethrow as a meaningful message, since the engine will wrap anything thrown."],"exampleFix":"// before\ncontext.publishFile(\"report.html\", MediaType.TEXT_HTML, path -> {\n    Files.writeString(path, buildHtml()); // buildHtml() may throw -> wrapped as 'Failed to publish path'\n});\n// after\ncontext.publishFile(\"report.html\", MediaType.TEXT_HTML, path -> {\n    String html;\n    try { html = buildHtml(); }\n    catch (Exception e) { throw new IOException(\"Failed to build report HTML\", e); }\n    Files.writeString(path, html);\n});","handlingStrategy":"try-catch","validationCode":"// Validate writability before calling publishFile\nPath outDir = Paths.get(System.getProperty(\"junit.jupiter.output.dir\", \"build/reports\"));\nif (!Files.isWritable(outDir)) {\n    throw new IllegalStateException(\"Output dir not writable: \" + outDir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    context.publishFile(\"report.html\", MediaType.TEXT_HTML, this::writeReport);\n} catch (JUnitException e) {\n    Throwable cause = e.getCause();\n    log.error(\"publishFile failed: {}\", cause.getMessage());\n    // fall back to in-test reporting or rethrow\n}","preventionTips":["Make publishFile actions self-contained: open and close all streams inside the lambda.","Pre-check that the configured output directory is writable.","Throw IOException with a clear message from the action so the wrapped cause is actionable."],"tags":["junit-jupiter","extension","publishing","io","report-entry"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}