apple/pkl · error · CliException

I/O error writing file `$outputFile`. Cause

Error message

I/O error writing file `$outputFile`.
Cause: ${e.message}

What it means

CliKotlinCodeGenerator wraps an IOException raised while writing a generated .kt file to the output directory into a CliException. It means the file could not be created or written (permissions, missing path component, disk, or target being a directory).

Solutions

  1. Check write permissions on the --output-dir and its parents; chmod/chown as needed.
  2. Ensure the output path is a directory and does not collide with an existing file of the same name.
  3. Verify free disk space and that the mount is not read-only.
  4. Re-run the generator; if on a network FS, retry after connectivity is restored.

Example fix

// before
pkl codegen kotlin --output-dir /usr/local/lib api.pkl
// after
pkl codegen kotlin --output-dir ./generated api.pkl
Defensive patterns

Strategy: validation

Validate before calling

val out = options.outputDir
require(!Files.exists(out) || Files.isDirectory(out)) { "output dir is a file: $out" }
require(Files.isWritable(out.takeIf { Files.exists(it) } ?: out.toAbsolutePath().parent)) {
  "output dir not writable: $out"
}
require(Files.getFileStore(out).totalSpace - Files.getFileStore(out).usableSpace < /* sane cap */) { "check disk space" }

Type guard

fun Path.isWritableDir(): Boolean =
  Files.isDirectory(this) && Files.isWritable(this)

Try / catch

try {
  generator.generateAndWrite(module)
} catch (e: CliException) {
  if (e.message?.startsWith("I/O error writing file") == true) {
    logger.error("Check permissions/disk for output dir: ${e.message}")
  } else throw e
}

Prevention

When it happens

Trigger: Kotlin codegen CLI (doRun) calls createParentDirectories().writeString(...) on options.outputDir.resolve(fileName) and the underlying write throws IOException.

Common situations: Output directory is read-only or owned by another user; outputDir path resolves onto an existing file; disk full; network filesystem hiccup; running in a container with a read-only mount.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at pkl-codegen-kotlin/src/main/kotlin/org/pkl/codegen/kotlin/CliKotlinCodeGenerator.kt:44

/** API for the Kotlin code generator CLI. */
class CliKotlinCodeGenerator(private val options: CliKotlinCodeGeneratorOptions) :
  CliCommand(options.base) {

  override fun doRun() {
    val builder = evaluatorBuilder()

    try {
      builder.build().use { evaluator ->
        for (moduleUri in options.base.normalizedSourceModules) {
          val schema = evaluator.evaluateSchema(ModuleSource.uri(moduleUri))
          val codeGenerator = KotlinCodeGenerator(schema, options.toKotlinCodeGeneratorOptions())
          try {
            for ((fileName, fileContents) in codeGenerator.output) {
              val outputFile = options.outputDir.resolve(fileName)
              try {
                outputFile.createParentDirectories().writeString(fileContents)
              } catch (e: IOException) {
                throw CliException("I/O error writing file `$outputFile`.\nCause: ${e.message}")
              }
            }
          } catch (e: KotlinCodeGeneratorException) {
            throw CliException(e.message!!)
          }
        }
      }
    } finally {
      Closeables.closeQuietly(builder.moduleKeyFactories)
      Closeables.closeQuietly(builder.resourceReaders)
    }
  }
}

View on GitHub (pinned to f3efcbfc9b)