{"record":{"id":"c1060b7b85b1cde7","repo":"apple/pkl","slug":"cannot-generate-java-enum-class-for-pkl-type-alias-c1060b","errorCode":null,"errorMessage":"Cannot generate Java enum class for Pkl type alias `${typeAlias.displayName}` because string literal types \"$firstLiteral\" and \"$secondLiteral\" would both be converted to enum constant name `$enumConstantName`.","messagePattern":"Cannot generate Java enum class for Pkl type alias `(.+?)` because string literal types \"\\$firstLiteral\" and \"\\$secondLiteral\" would both be converted to enum constant name `\\$enumConstantName`\\.","errorType":"exception","errorClass":"JavaCodeGeneratorException","httpStatus":null,"severity":"error","filePath":"pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt","lineNumber":665,"sourceCode":"      .initializer(\"0L\")\n      .build()\n  }\n\n  private fun generateEnumTypeSpec(\n    typeAlias: TypeAlias,\n    stringLiterals: Set<String>,\n  ): TypeSpec.Builder {\n    val enumConstantToPklNames =\n      stringLiterals\n        .groupingBy { literal ->\n          CodeGeneratorUtils.toEnumConstantName(literal)\n            ?: throw JavaCodeGeneratorException(\n              \"Cannot generate Java enum class for Pkl type alias `${typeAlias.displayName}` \" +\n                \"because string literal type \\\"$literal\\\" cannot be converted to a valid enum constant name.\"\n            )\n        }\n        .reduce { enumConstantName, firstLiteral, secondLiteral ->\n          throw JavaCodeGeneratorException(\n            \"Cannot generate Java enum class for Pkl type alias `${typeAlias.displayName}` \" +\n              \"because string literal types \\\"$firstLiteral\\\" and \\\"$secondLiteral\\\" \" +\n              \"would both be converted to enum constant name `$enumConstantName`.\"\n          )\n        }\n\n    val builder =\n      TypeSpec.enumBuilder(typeAlias.simpleName)\n        .addModifiers(Modifier.PUBLIC)\n        .addField(String::class.java, \"value\", Modifier.PRIVATE)\n        .addMethod(\n          MethodSpec.constructorBuilder()\n            .addModifiers(Modifier.PRIVATE)\n            .addParameter(String::class.java, \"value\")\n            .addStatement(\"this.value = value\")\n            .build()\n        )\n        .addMethod(","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt#L647-L683","documentation":"During enum generation, distinct string literals that sanitize to the same Java enum constant name would collide (e.g. \"foo-bar\" and \"foo_bar\" both becoming FOO_BAR). The reduce step detects the collision and aborts, because two enum constants cannot share a name.","triggerScenarios":"A string-literal type alias contains two literals that toEnumConstantName normalizes to the identical identifier — differing only in case, separators (-, ., spaces), or other characters stripped during sanitization.","commonSituations":"Modules mixing kebab-case and snake_case variants of the same word (\"log-level\" vs \"log_level\"), literals differing only in case, or values differing only by punctuation.","solutions":["Rename one of the conflicting literals in the Pkl module so they produce distinct enum names.","Normalize your value set to one convention (e.g. all kebab-case, no case-only differences).","Check which literals collide by applying Java identifier sanitization rules manually.","Fall back to String representation for the alias if the values cannot be changed."],"exampleFix":"// before (Pkl)\ntype Level = \"log-level\" | \"log_level\"\n// after\ntype Level = \"log-level\" | \"logLevel\"","handlingStrategy":"validation","validationCode":"val names = literals.map { CodeGeneratorUtils.toEnumConstantName(it) }; require(names.distinct().size == names.size) { \"enum name collision: $literals\" }","typeGuard":"fun Set<String>.hasEnumCollisions() = groupingBy { CodeGeneratorUtils.toEnumConstantName(it)!! }.eachCount().any { it.value > 1 }","tryCatchPattern":"try { generate() } catch (e: JavaCodeGeneratorException) { if (\"would both be converted\" in e.message!!) renameCollidingLiterals() else throw e }","preventionTips":["Keep string-literal unions in one naming convention","Avoid values differing only by case or separators","Deduplicate literals after sanitization in a pre-check"],"tags":["codegen","enum","collision"],"backgroundTag":"invalid-enum-value","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"}