{"id":"1dfee3b1eef67c37","repo":"junit-team/junit5","slug":"failed-to-copy-files-to-the-output-directory","errorCode":null,"errorMessage":"Failed to copy files to the output directory","messagePattern":"Failed to copy files to the output directory","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java","lineNumber":160,"sourceCode":"\t@API(status = MAINTAINED, since = \"5.13.3\")\n\tdefault void publishDirectory(Path directory) {\n\t\tPreconditions.notNull(directory, \"directory must not be null\");\n\t\tPreconditions.condition(Files.exists(directory), () -> \"directory must exist: \" + directory);\n\t\tPreconditions.condition(Files.isDirectory(directory), () -> \"path must represent a directory: \" + directory);\n\t\tpublishDirectory(directory.getFileName().toString(), path -> {\n\t\t\ttry (Stream<Path> stream = Files.walk(directory)) {\n\t\t\t\tstream.forEach(source -> {\n\t\t\t\t\tPath destination = path.resolve(directory.relativize(source));\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (Files.isDirectory(source)) {\n\t\t\t\t\t\t\tFiles.createDirectories(destination);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tFiles.copy(source, destination, REPLACE_EXISTING);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IOException e) {\n\t\t\t\t\t\tthrow new UncheckedIOException(\"Failed to copy files to the output directory\", e);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Publish a file with the supplied name and media type written by the supplied\n\t * action and attach it to the current test or container.\n\t *\n\t * <p>The {@link Path} passed to the supplied action will be relative to the\n\t * report output directory, but it is up to the action to write the file.\n\t *\n\t * @param name the name of the file to be published; never {@code null} or\n\t * blank and must not contain any path separators\n\t * @param mediaType the media type of the file; never {@code null}; use\n\t * {@link org.junit.jupiter.api.extension.MediaType#APPLICATION_OCTET_STREAM}\n\t * if unknown","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-jupiter-api/src/main/java/org/junit/jupiter/api/TestReporter.java#L142-L178","documentation":"Thrown as UncheckedIOException inside TestReporter.publishDirectory(Path) when copying a file from the source directory tree to the report output directory fails with an IOException (Files.copy or Files.createDirectories inside the Files.walk loop). It wraps the underlying I/O error so the test fails loudly rather than silently producing a partial directory.","triggerScenarios":"Calling testReporter.publishDirectory(dirPath) where dirPath is readable but the report output directory is not writable, a source file is deleted/made unreadable during the walk, the output filesystem is full, or a destination path cannot be created (e.g., a name collision with an existing file where a directory is expected).","commonSituations":"Tests that publish generated artifacts (screenshots, coverage dumps, HTML reports) to a report dir; CI sandboxes where the output root is read-only or ephemeral; parallel tests racing on the same output filename.","solutions":["Verify the report output directory is writable and has enough free space before publishing.","Ensure the source directory is stable (no concurrent mutation) during publishDirectory.","Use unique directory/file names per test (e.g., prefixed with the test display name) to avoid parallel write collisions.","If the wrapped IOException is transient (e.g., short disk hiccup), re-run the test on a healthy worker."],"exampleFix":"// before\ntestReporter.publishDirectory(Path.of(\"build/output\")); // fails if build/output not writable\n\n// after — preflight the source and ensure the output root is writable\nPath src = Path.of(\"build/output\");\nif (!Files.isReadable(src) || !Files.isDirectory(src)) {\n    throw new IllegalStateException(\"source dir missing: \" + src);\n}\ntestReporter.publishDirectory(src);","handlingStrategy":"try-catch","validationCode":"Path src = /* directory to publish */;\nif (!Files.isDirectory(src) || !Files.isReadable(src)) {\n    throw new IllegalStateException(\"source directory not readable: \" + src);\n}\n// best-effort stability check: snapshot the entry list\nlong count;\ntry (var s = Files.walk(src)) { count = s.count(); }\n// ensure report output root is writable by publishing a tiny probe first if unsure","typeGuard":null,"tryCatchPattern":"try {\n    testReporter.publishDirectory(src);\n} catch (java.io.UncheckedIOException e) {\n    // log and fall back to publishing individual files, or mark the test as incomplete\n    System.err.println(\"publishDirectory failed: \" + e.getCause());\n    throw e;\n}","preventionTips":["Ensure the report output directory is writable before publishing (set junit.platform.output.* / launcher config correctly).","Do not mutate the source directory while publishDirectory is running.","Use unique filenames per test to avoid parallel write races."],"tags":["io","test-reporter","filesystem","publish-directory","junit-jupiter"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}