apple/pkl · error · CliException

Output path `$outputDir` exists and is not a directory.

Error message

Output path `$outputDir` exists and is not a directory.

What it means

Before writing multiple-file output, CliCommandRunner.writeMultipleFileOutput verifies that the working-directory-derived output path, if it already exists, is a directory. This error means the target output location exists as a regular file (or other non-directory), so per-file outputs cannot be written beneath it.

Source

Thrown at pkl-cli/src/main/kotlin/org/pkl/cli/CliCommandRunner.kt:116

  }

  /**
   * Renders the command's `output.files`, writing each entry as a file.
   *
   * File paths are written to the standard error stream.
   *
   * Unlike CliEvaluator, command outputs write relative to --working-dir and may write files
   * 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()

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Delete or rename the existing file at the output path so the tool can create a directory there.
  2. Point the output path/working dir at an empty directory instead.
  3. If the file is a previous single-file output you still need, move it elsewhere before re-running.
  4. Check the path in your script/CI config — it may reference a file rather than a directory.

Example fix

# before
$ pkl eval -m out ...   # where `out` is an existing file
rm out
# after
$ mkdir -p out && pkl eval -m out ...
Defensive patterns

Strategy: validation

Validate before calling

import java.nio.file.*
val p = Path.of(outputPath)
require(!(Files.exists(p) && !Files.isDirectory(p))) { "Output path $p exists and is not a directory" }

Try / catch

try {
  runner.writeMultipleFileOutput(outputFiles)
} catch (e: CliException) {
  System.err.println(e.message)
}

Prevention

When it happens

Trigger: Running a pkl command with multiple-file output (output.files) while options.normalizedWorkingDir points at an existing regular file — e.g. a stale file created by a previous single-file-output run at the same path.

Common situations: Switching from single-file output to multiple-file output without removing the old output file; a script that created a file where a directory is expected; wrong --output-path or working directory flag.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/136a28e9590ccba0. Report an issue: GitHub.