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
- Check write permissions on the --output-dir and its parents; chmod/chown as needed.
- Ensure the output path is a directory and does not collide with an existing file of the same name.
- Verify free disk space and that the mount is not read-only.
- 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
- Verify --output-dir exists, is a directory, and is writable before running codegen
- Avoid output paths inside read-only containers/mounts
- Watch disk space in CI runners before large generation runs
- Do not let output file names collide with existing files used for other purposes
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
- I/O error writing `$path`.
- Cannot generate Kotlin code for a Pkl standard library…
- Cannot generate Kotlin enum class for Pkl type alias
- Cannot generate Kotlin enum class for Pkl type alias
- Failed to write to $depsFile
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)