apple/pkl · error · CliException
Output file conflict: `output.files` entries `"${previousOut
Error message
Output file conflict: `output.files` entries `"${previousOutput}"` and `"$pathSpec"` resolve to the same file path `$realPath`. What it means
When writing per-module file outputs, CliCommandRunner tracks real paths already written; this error means two different `output.files` pathSpec entries (from the same or different module outputs) normalize/resolve to the same physical file, so the later entry would silently overwrite the earlier one. The CLI refuses rather than allow ambiguity.
Source
Thrown at pkl-cli/src/main/kotlin/org/pkl/cli/CliCommandRunner.kt:124
* anywhere in the filesystem. This is intentionally less sandboxed than `pkl eval` and directly
* targets the capabilities of CLI tools written in general purpose languages. Pkl commands should
* therefore be treated as untrusted code the way that any other CLI tool would be.
*/
fun writeMultipleFileOutput(outputFiles: Map<String, FileOutput>) {
if (outputFiles.isEmpty()) return
val writtenFiles = mutableMapOf<Path, String>()
val outputDir = options.normalizedWorkingDir
if (outputDir.exists() && !outputDir.isDirectory()) {
throw CliException("Output path `$outputDir` exists and is not a directory.")
}
for ((pathSpec, fileOutput) in outputFiles) {
checkPathSpec(pathSpec)
val resolvedPath = outputDir.resolve(pathSpec).normalize()
val realPath = if (resolvedPath.exists()) resolvedPath.toRealPath() else resolvedPath
val previousOutput = writtenFiles[realPath]
if (previousOutput != null) {
throw CliException(
"Output file conflict: `output.files` entries `\"${previousOutput}\"` and `\"$pathSpec\"` resolve to the same file path `$realPath`."
)
}
if (realPath.isDirectory()) {
throw CliException(
"Output file conflict: `output.files` entry `\"$pathSpec\"` resolves to file path `$realPath`, which is a directory."
)
}
writtenFiles[realPath] = pathSpec
realPath.createParentDirectories()
realPath.writeBytes(fileOutput.bytes)
val displayPath =
if (Path.of(pathSpec).isAbsolute) pathSpec
else IoUtils.relativize(resolvedPath, currentWorkingDir).toString()
errStream.writeText(displayPath + IoUtils.getLineSeparator())
errStream.flush()
}
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Make each `output.files` entry resolve to a unique path — include `%{moduleDir}` or `%{moduleName}` plus distinguishing segments in pathSpecs.
- Inspect the resolved realPath in the message to find which two entries collide.
- Avoid symlinks or overlapping output directories that make distinct specs share one real path.
- Remove duplicate entries in the `output.files` mapping.
Example fix
// before (output.files in Pkl) ["out.json"] = myOutput ["./out.json"] = otherOutput // same real path // after ["first/out.json"] = myOutput ["second/out.json"] = otherOutput
Defensive patterns
Strategy: validation
Validate before calling
val resolved = pathSpecs.map { outputDir.resolve(it).normalize().toRealPath() }
require(resolved.distinct().size == resolved.size) { "Duplicate resolved output paths: ${resolved.groupingBy { it }.eachCount().filterValues { it > 1 }}" } Try / catch
try {
runner.writeMultipleFileOutput(outputFiles)
} catch (e: CliException) {
if (e.message?.contains("conflict") == true) {
// dedupe output.files entries and retry
}
} Prevention
- Make `output.files` pathSpecs unique, including %{moduleDir} when multiple modules share basenames.
- Avoid symlinked output directories that collapse distinct paths.
- Review output.files mappings for duplicate or equivalent entries.
When it happens
Trigger: Two `output.files` mappings whose pathSpecs resolve to the same path — e.g. `"a.json"` and `"./a.json"`, symlinks collapsing to one real path, or `"%{moduleName}.json"` patterns that produce identical names for modules with the same name in different directories.
Common situations: Placeholder patterns like `%{moduleName}` colliding when two evaluated modules share a basename; symlinked output directories; duplicate pathSpec entries in the Pkl config.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Output file conflict: `output.files` entry `"$pathSpec"` res
- Output path `$outputDir` exists and is not a directory.
- Output file `$outputFile` is a directory. Did you mean `--mu
- Output path `$outputDir` exists and is not a directory.
- Failed to write to $depsFile: ${e.message}
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/eea7f04e1a8693c3.
Report an issue: GitHub.