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

  1. 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.
  2. If the union is intended as a constrained set, define it as `typealias X = "a"|"b"` so isRepresentableAsString succeeds.
  3. 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

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


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 key

View on GitHub (pinned to f3efcbfc9b)