{"record":{"id":"479a46197273fc6c","repo":"apple/pkl","slug":"i-o-error-writing-file-outputfile-cause-e-m-479a46","errorCode":null,"errorMessage":"I/O error writing file `$outputFile`.\nCause: ${e.message}","messagePattern":"I/O error writing file `\\$outputFile`\\.\nCause: (.+?)","errorType":"exception","errorClass":"CliException","httpStatus":null,"severity":"error","filePath":"pkl-codegen-kotlin/src/main/kotlin/org/pkl/codegen/kotlin/CliKotlinCodeGenerator.kt","lineNumber":44,"sourceCode":"/** API for the Kotlin code generator CLI. */\nclass CliKotlinCodeGenerator(private val options: CliKotlinCodeGeneratorOptions) :\n  CliCommand(options.base) {\n\n  override fun doRun() {\n    val builder = evaluatorBuilder()\n\n    try {\n      builder.build().use { evaluator ->\n        for (moduleUri in options.base.normalizedSourceModules) {\n          val schema = evaluator.evaluateSchema(ModuleSource.uri(moduleUri))\n          val codeGenerator = KotlinCodeGenerator(schema, options.toKotlinCodeGeneratorOptions())\n          try {\n            for ((fileName, fileContents) in codeGenerator.output) {\n              val outputFile = options.outputDir.resolve(fileName)\n              try {\n                outputFile.createParentDirectories().writeString(fileContents)\n              } catch (e: IOException) {\n                throw CliException(\"I/O error writing file `$outputFile`.\\nCause: ${e.message}\")\n              }\n            }\n          } catch (e: KotlinCodeGeneratorException) {\n            throw CliException(e.message!!)\n          }\n        }\n      }\n    } finally {\n      Closeables.closeQuietly(builder.moduleKeyFactories)\n      Closeables.closeQuietly(builder.resourceReaders)\n    }\n  }\n}\n","sourceCodeStart":26,"sourceCodeEnd":58,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-codegen-kotlin/src/main/kotlin/org/pkl/codegen/kotlin/CliKotlinCodeGenerator.kt#L26-L58","documentation":"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).","triggerScenarios":"Kotlin codegen CLI (doRun) calls createParentDirectories().writeString(...) on options.outputDir.resolve(fileName) and the underlying write throws IOException.","commonSituations":"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.","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."],"exampleFix":"// before\npkl codegen kotlin --output-dir /usr/local/lib api.pkl\n// after\npkl codegen kotlin --output-dir ./generated api.pkl","handlingStrategy":"validation","validationCode":"val out = options.outputDir\nrequire(!Files.exists(out) || Files.isDirectory(out)) { \"output dir is a file: $out\" }\nrequire(Files.isWritable(out.takeIf { Files.exists(it) } ?: out.toAbsolutePath().parent)) {\n  \"output dir not writable: $out\"\n}\nrequire(Files.getFileStore(out).totalSpace - Files.getFileStore(out).usableSpace < /* sane cap */) { \"check disk space\" }","typeGuard":"fun Path.isWritableDir(): Boolean =\n  Files.isDirectory(this) && Files.isWritable(this)","tryCatchPattern":"try {\n  generator.generateAndWrite(module)\n} catch (e: CliException) {\n  if (e.message?.startsWith(\"I/O error writing file\") == true) {\n    logger.error(\"Check permissions/disk for output dir: ${e.message}\")\n  } else throw e\n}","preventionTips":["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"],"tags":["kotlin","codegen","io","file-write"],"backgroundTag":"file-write-failed","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"}