apple/pkl · error · JavaCodeGeneratorException
Pkl union types are not supported by the Java code…
Error message
Pkl union types are not supported by the Java code generator.
What it means
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.
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.
Example fix
// before (Pkl)
amount: Int|String
// after
open class Amount { ... } // or typealias of string literals Defensive patterns
Strategy: validation
Validate before calling
// Before invoking Java codegen, inspect the module schema types
moduleSchema.properties.values.forEach { p ->
val t = p.type
if (t is PType.Union && !CodeGeneratorUtils.isRepresentableAsString(t)) {
throw IllegalArgumentException("Property ${p.name} uses an unrepresentable union type")
}
} Type guard
fun isUnionSafeForJava(t: PType?): Boolean = t !is PType.Union || CodeGeneratorUtils.isRepresentableAsString(t)
Try / catch
try {
javaCodeGenerator.generate(module)
} catch (e: JavaCodeGeneratorException) {
if (e.message?.contains("union types") == true) {
logger.warn("Module uses unsupported union types: ${e.message}")
} else throw e
} Prevention
- 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
When it happens
Trigger: 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`).
Common situations: Pkl schemas using union types for constrained values (`1|2|3`, `"a"|Int`), often inherited from stdlib or shared modules, being generated to Java.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Pkl union types are not supported by the Kotlin code…
- Pkl function types are not supported by the Kotlin code…
- Pkl ` ` types are not supported by the Kotlin code…
- Annotation `$fqn` is not a valid Java class. The name of…
- Cannot convert Pkl duration `this` to `java.time.Duration`.
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/3b5332e5716bced8.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt:893
)
} else {
// reference generated enum class
typeAlias.toJavaPoetName().nullableIf(nullable)
}
} else {
// inline type alias
aliasedType.toJavaPoetName(nullable)
}
}
}
is PType.Function ->
throw JavaCodeGeneratorException(
"Pkl function types are not supported by the Java code generator."
)
is PType.Union ->
if (CodeGeneratorUtils.isRepresentableAsString(this)) STRING.nullableIf(nullable)
else
throw JavaCodeGeneratorException(
"Pkl union types are not supported by the Java code generator."
)
else ->
// should never encounter PType.TypeVariableNode because it can only occur in stdlib classes
throw AssertionError("Encountered unexpected PType subclass: $this")
}
private fun TypeName.nullableIf(isNullable: Boolean): TypeName =
if (isPrimitive && isNullable) box()
else if (isPrimitive || isNullable) this else annotated(nonNullAnnotation)
private fun TypeName.boxIf(shouldBox: Boolean): TypeName = if (shouldBox) box() else this
private fun <T> renameIfReservedWord(map: Map<String, T>): Map<String, T> {
return map.mapKeys { (key, _) ->
if (key in javaReservedWords) {
generateSequence("_$key") { "_$it" }.first { it !in map.keys }
} else keyView on GitHub (pinned to f3efcbfc9b)