{"record":{"id":"3b5332e5716bced8","repo":"apple/pkl","slug":"pkl-union-types-are-not-supported-by-the-java-code","errorCode":null,"errorMessage":"Pkl union types are not supported by the Java code generator.","messagePattern":"Pkl union types are not supported by the Java code generator\\.","errorType":"exception","errorClass":"JavaCodeGeneratorException","httpStatus":null,"severity":"error","filePath":"pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt","lineNumber":893,"sourceCode":"                )\n              } else {\n                // reference generated enum class\n                typeAlias.toJavaPoetName().nullableIf(nullable)\n              }\n            } else {\n              // inline type alias\n              aliasedType.toJavaPoetName(nullable)\n            }\n          }\n        }\n      is PType.Function ->\n        throw JavaCodeGeneratorException(\n          \"Pkl function types are not supported by the Java code generator.\"\n        )\n      is PType.Union ->\n        if (CodeGeneratorUtils.isRepresentableAsString(this)) STRING.nullableIf(nullable)\n        else\n          throw JavaCodeGeneratorException(\n            \"Pkl union types are not supported by the Java code generator.\"\n          )\n      else ->\n        // should never encounter PType.TypeVariableNode because it can only occur in stdlib classes\n        throw AssertionError(\"Encountered unexpected PType subclass: $this\")\n    }\n\n  private fun TypeName.nullableIf(isNullable: Boolean): TypeName =\n    if (isPrimitive && isNullable) box()\n    else if (isPrimitive || isNullable) this else annotated(nonNullAnnotation)\n\n  private fun TypeName.boxIf(shouldBox: Boolean): TypeName = if (shouldBox) box() else this\n\n  private fun <T> renameIfReservedWord(map: Map<String, T>): Map<String, T> {\n    return map.mapKeys { (key, _) ->\n      if (key in javaReservedWords) {\n        generateSequence(\"_$key\") { \"_$it\" }.first { it !in map.keys }\n      } else key","sourceCodeStart":875,"sourceCodeEnd":911,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt#L875-L911","documentation":"The Java code generator cannot represent a Pkl union type that is not convertible to a string. It only supports unions whose members are string literals (emitted as a String property with Javadoc); anything else has no natural Java representation, so JavaCodeGeneratorException is thrown from toJavaPoetName.","triggerScenarios":"Running Java codegen on a Pkl module whose property or type alias resolves to PType.Union whose members are not all representable as strings (e.g. `Int|String`, `Listing<String>|Int`).","commonSituations":"Pkl schemas using union types for constrained values (`1|2|3`, `\"a\"|Int`), often inherited from stdlib or shared modules, being generated to Java.","solutions":["Replace the union type in the Pkl module with a type alias of string literals (which becomes a String) or a concrete class/sealed-style set of classes.","If the union is intended as a constrained set, define it as `typealias X = \"a\"|\"b\"` so isRepresentableAsString succeeds.","Generate to Kotlin instead, or handle the type manually outside codegen."],"exampleFix":"// before (Pkl)\namount: Int|String\n// after\nopen class Amount { ... } // or typealias of string literals","handlingStrategy":"validation","validationCode":"// Before invoking Java codegen, inspect the module schema types\nmoduleSchema.properties.values.forEach { p ->\n  val t = p.type\n  if (t is PType.Union && !CodeGeneratorUtils.isRepresentableAsString(t)) {\n    throw IllegalArgumentException(\"Property ${p.name} uses an unrepresentable union type\")\n  }\n}","typeGuard":"fun isUnionSafeForJava(t: PType?): Boolean =\n  t !is PType.Union || CodeGeneratorUtils.isRepresentableAsString(t)","tryCatchPattern":"try {\n  javaCodeGenerator.generate(module)\n} catch (e: JavaCodeGeneratorException) {\n  if (e.message?.contains(\"union types\") == true) {\n    logger.warn(\"Module uses unsupported union types: ${e.message}\")\n  } else throw e\n}","preventionTips":["Prefer string-literal typealiases over arbitrary unions in modules destined for Java codegen","Lint Pkl schemas for non-string unions before wiring codegen into CI","Document which Pkl type constructs are Java-codegen safe for schema authors"],"tags":["java","codegen","union-type","unsupported-type"],"backgroundTag":"unsupported-operation","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"}