{"record":{"id":"39998499dfb7e743","repo":"apple/pkl","slug":"output-file-conflict-output-files-entry-path-399984","errorCode":null,"errorMessage":"Output file conflict: `output.files` entry `\"$pathSpec\"` in module `$moduleUri` resolves to file path `$realPath`, which is a directory.","messagePattern":"Output file conflict: `output\\.files` entry `\"\\$pathSpec\"` in module `\\$moduleUri` resolves to file path `\\$realPath`, which is a directory\\.","errorType":"exception","errorClass":"CliException","httpStatus":null,"severity":"error","filePath":"pkl-cli/src/main/kotlin/org/pkl/cli/CliEvaluator.kt","lineNumber":256,"sourceCode":"        val output = evaluator.evaluateOutputFiles(moduleSource)\n        val realOutputDir = if (outputDir.exists()) outputDir.toRealPath() else outputDir\n\n        for ((pathSpec, fileOutput) in output) {\n          checkPathSpec(pathSpec)\n          val (realPath, resolvedPath) = realOutputDir.resolveRealPath(Path.of(pathSpec))\n          if (!realPath.startsWith(realOutputDir)) {\n            throw CliException(\n              \"Output file conflict: `output.files` entry `\\\"$pathSpec\\\"` in module `$moduleUri` resolves to file path `$realPath`, which is outside output directory `$realOutputDir`.\"\n            )\n          }\n          val previousOutput = writtenFiles[realPath]\n          if (previousOutput != null) {\n            throw CliException(\n              \"Output file conflict: `output.files` entries `\\\"${previousOutput.pathSpec}\\\"` in module `${previousOutput.moduleUri}` and `\\\"$pathSpec\\\"` in module `$moduleUri` resolve to the same file path `$realPath`.\"\n            )\n          }\n          if (realPath.isDirectory()) {\n            throw CliException(\n              \"Output file conflict: `output.files` entry `\\\"$pathSpec\\\"` in module `$moduleUri` resolves to file path `$realPath`, which is a directory.\"\n            )\n          }\n          writtenFiles[realPath] = OutputFile(pathSpec, moduleUri)\n          realPath.createParentDirectories()\n          realPath.writeBytes(fileOutput.bytes)\n          outputStream.writeText(\n            IoUtils.relativize(resolvedPath, currentWorkingDir).toString() +\n              IoUtils.getLineSeparator()\n          )\n          outputStream.flush()\n        }\n      }\n    }\n  }\n\n  /**\n   * Resolves [rel] against this Path name-by-name. At each step, the real path is resolved if the","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-cli/src/main/kotlin/org/pkl/cli/CliEvaluator.kt#L238-L274","documentation":"An `output.files` entry resolves to a path that currently is a directory on disk, so the CLI cannot write bytes to it and throws from writeMultipleFileOutput. This happens after the outside-directory and duplicate-path checks pass.","triggerScenarios":"Path spec `foo` when `foo/` exists as a directory in the output directory, or a path spec that omits the filename while a directory of that name exists (e.g. `output.files { [\"build\"] }`).","commonSituations":"After refactoring, an output previously written to `build/out.json` becomes `build`, which is now a directory; or users mistake the files map value for a directory target instead of a file path.","solutions":["Change the path spec to include a filename inside the directory, e.g. `build/output.json`.","Remove or rename the existing directory at the resolved path if it is stale.","Check the resolved path printed in the message to confirm what the CLI attempted to write."],"exampleFix":"// before\noutput.files { [\"build\"] }\n// after\noutput.files { [\"build/output.json\"] }","handlingStrategy":"validation","validationCode":"val target = outDir.resolveRealPath(pathSpec).realPath\ncheck(!java.nio.file.Files.isDirectory(target)) { \"$pathSpec resolves to a directory\" }","typeGuard":null,"tryCatchPattern":"try {\n  pklCli.runEval(args)\n} catch (e: CliException) {\n  if (\"which is a directory\" in (e.message ?: \"\")) fixPathToFileName(e)\n  else throw e\n}","preventionTips":["Always include a filename in output.files path specs.","Clean stale directories from the output dir before evaluating.","After renames, check the output dir for paths that became directories."],"tags":["cli","file-conflict","directory"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}