{"record":{"id":"c5f1c755f44540a6","repo":"apple/pkl","slug":"cannot-generate-java-enum-class-for-pkl-type-alias","errorCode":null,"errorMessage":"Cannot generate Java enum class for Pkl type alias `${typeAlias.displayName}` because string literal type \"$literal\" cannot be converted to a valid enum constant name.","messagePattern":"Cannot generate Java enum class for Pkl type alias `(.+?)` because string literal type \"\\$literal\" cannot be converted to a valid enum constant name\\.","errorType":"exception","errorClass":"JavaCodeGeneratorException","httpStatus":null,"severity":"error","filePath":"pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt","lineNumber":659,"sourceCode":"    return generateClass()\n  }\n\n  private fun generateSerialVersionUIDField(): FieldSpec {\n    return FieldSpec.builder(Long::class.java, \"serialVersionUID\", Modifier.PRIVATE)\n      .addModifiers(Modifier.STATIC, Modifier.FINAL)\n      .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()","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt#L641-L677","documentation":"When a string-literal type alias is represented as a Java enum, each string literal must map to a valid enum constant name via CodeGeneratorUtils.toEnumConstantName. Literals that cannot be converted (e.g. empty or entirely invalid characters) abort enum generation for that type alias.","triggerScenarios":"A type alias like `type Direction = \"\" | \"up\" | ...` where one literal produces null from toEnumConstantName — typically empty strings or literals consisting only of characters not usable in a Java identifier.","commonSituations":"Pkl modules using `\"\"` as a sentinel value in string unions, literals made solely of digits or punctuation (e.g. `\"-\"`, `\"123\"`), or locale-specific strings with only symbols.","solutions":["Change the offending string literal in the Pkl module to something convertible (letters/underscores).","Avoid empty-string literals in the union; use a named value like \"none\".","Check for literals that reduce to only symbols or digits after sanitization and rename them.","Disable enum representation for that alias (represent it as String) if the literal must stay as-is."],"exampleFix":"// before (Pkl)\ntype Status = \"\" | \"active\"\n// after\ntype Status = \"unknown\" | \"active\"","handlingStrategy":"validation","validationCode":"fun literalIsEnumSafe(l: String) = l.isNotEmpty() && CodeGeneratorUtils.toEnumConstantName(l) != null","typeGuard":"fun String.toEnumNameOrNull(): String? = takeIf { it.isNotEmpty() }?.let { CodeGeneratorUtils.toEnumConstantName(it) }","tryCatchPattern":"try { generate() } catch (e: JavaCodeGeneratorException) { if (\"cannot be converted to a valid enum constant name\" in e.message!!) adjustLiterals() else throw e }","preventionTips":["Avoid empty/symbol-only string literals in string-literal unions","Use letter-containing sentinel values like \"unknown\"","Preview enum names for all literals before generating"],"tags":["codegen","enum","type-alias"],"backgroundTag":"invalid-identifier-format","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"}