{"record":{"id":"b977c81272ff19b8","repo":"junit-team/junit5","slug":"failed-to-create-output-dir","errorCode":null,"errorMessage":"Failed to create output dir","messagePattern":"Failed to create output dir","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java","lineNumber":46,"sourceCode":"import org.apiguardian.api.API;\nimport org.junit.platform.commons.util.StringUtils;\n\n@API(status = INTERNAL, since = \"1.9\")\npublic class OutputDir {\n\n\tprivate static final Pattern OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN = Pattern.compile(\n\t\tPattern.quote(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER));\n\n\tpublic static OutputDir create(Optional<String> customDir) {\n\t\treturn create(customDir, () -> Path.of(\".\"));\n\t}\n\n\tstatic OutputDir create(Optional<String> customDir, Supplier<Path> currentWorkingDir) {\n\t\ttry {\n\t\t\treturn createSafely(customDir, currentWorkingDir);\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new UncheckedIOException(\"Failed to create output dir\", e);\n\t\t}\n\t}\n\n\t/**\n\t * Package private for testing purposes.\n\t */\n\tstatic OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir) throws IOException {\n\t\treturn createSafely(customDir, currentWorkingDir, new SecureRandom());\n\t}\n\n\tprivate static OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir,\n\t\t\tSecureRandom random) throws IOException {\n\t\tPath cwd = currentWorkingDir.get().toAbsolutePath();\n\t\tPath outputDir;\n\n\t\tif (customDir.isPresent() && StringUtils.isNotBlank(customDir.get())) {\n\t\t\toutputDir = cwd.resolve(expandPlaceholders(customDir.get(), random));\n\t\t}","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/junit-team/junit5/blob/f070c699a08b5d8393df9afd147af5c5e90bb21b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java#L28-L64","documentation":"Thrown as an UncheckedIOException by OutputDir.create() when the underlying createSafely() raises an IOException while resolving or creating the reporting output directory. OutputDir auto-detects the directory as 'target' (when pom.xml exists), 'build' (when a .gradle/.gradle.kts file exists), or the current working directory, unless 'junit.platform.reporting.output.dir' is set. The {uniqueNumber} placeholder is expanded before creation. This is an INTERNAL API (@API status = INTERNAL).","triggerScenarios":"Calling OutputDir.create(Optional.of(customDir)) or the no-arg create() when: the resolved directory path is not writable by the JVM user; the path contains illegal filesystem characters; Files.createDirectories() fails because a non-directory file already exists at that path; the parent filesystem is read-only; or the disk is full. The customDir value is resolved against the current working directory and its placeholders are expanded before mkdirs is attempted.","commonSituations":"Running the JVM as a user without write permission to the project root; pointing junit.platform.reporting.output.dir to a read-only mount or a path inside /opt or /etc; containerized runs where the cwd is an overlay read-only layer; CI agents with a small/full workspace; a file (not a directory) already occupies the target path; the cwd was deleted between build and test phases.","solutions":["Point junit.platform.reporting.output.dir to a known-writable absolute path, e.g. -Djunit.platform.reporting.output.dir=/tmp/junit-output.","Verify write permission on the auto-detected directory (target/ for Maven, build/ for Gradle, or cwd) and chmod/chown it for the JVM user.","Ensure no regular file occupies the intended directory path (Files.createDirectories fails if a file is there).","Free disk space on the volume hosting the output directory."],"exampleFix":"// before\n-Djunit.platform.reporting.output.dir=/opt/app/tests/out\n\n// after\n-Djunit.platform.reporting.output.dir=/var/tmp/junit-output","handlingStrategy":"try-catch","validationCode":"// Preflight: confirm the resolved output directory is creatable & writable.\nString custom = System.getProperty(\"junit.platform.reporting.output.dir\");\nPath base = (custom == null || custom.isBlank())\n        ? Path.of(\".\").toAbsolutePath()  // OutputDir auto-detects target/build/cwd\n        : Path.of(custom).toAbsolutePath();\nPath parent = base.getParent() != null ? base.getParent() : base;\nif (!Files.isWritable(parent)) {\n    throw new IllegalStateException(\"Output dir parent not writable: \" + parent);\n}","typeGuard":null,"tryCatchPattern":"// OutputDir.create throws UncheckedIOException (it is INTERNAL, so direct use is rare).\ntry {\n    OutputDir outputDir = OutputDir.create(Optional.ofNullable(customDir));\n} catch (UncheckedIOException e) {\n    // Log the cause IOException and fall back to a guaranteed-writable temp dir.\n    Path fallback = Files.createTempDirectory(\"junit-output\");\n    outputDir = OutputDir.create(Optional.of(fallback.toString()));\n}","preventionTips":["Set junit.platform.reporting.output.dir to an absolute path on a local writable volume.","Run a preflight Files.isWritable check on the directory's parent in CI before tests.","Make sure no regular file occupies the intended directory path.","Avoid network/overlay mounts for the output directory."],"tags":["filesystem","io","reporting","permissions","configuration"],"backgroundTag":null,"analyzedSha":"f070c699a08b5d8393df9afd147af5c5e90bb21b","analyzedAt":"2026-08-11T20:31:00.530Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}