apple/pkl · error · VmTypeMismatchException.Union
union type mismatch
Error message
union type mismatch
What it means
Pkl's UnionTypeNode checks a value against each member of a union type (e.g. `Int|String|Listing<Float>`). It tries every member, collecting each member's VmTypeMismatchException; if none succeeds, it throws VmTypeMismatchException.Union summarizing why every union member rejected the value. This is Pkl's standard 'value matches none of the union alternatives' type-check failure.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java:1088
// if enabled, re-execute type checks to generate power assertions
localContext.setInTypeTest(wasInTypeTest);
if (VmContext.get(this).getPowerAssertionsEnabled()
&& (!wasInTypeTest || localContext.hasActiveTracker())) {
for (var i = 0; i < elementTypeNodes.length; i++) {
var elementTypeNode = elementTypeNodes[i];
try {
if (shouldEagerCheck) {
elementTypeNode.executeEagerly(frame, value);
} else {
elementTypeNode.executeLazily(frame, value);
}
} catch (VmTypeMismatchException e) {
typeMismatches[i] = e;
}
}
}
throw new VmTypeMismatchException.Union(sourceSection, value, this, typeMismatches);
}
@Override
public Object executeEagerly(VirtualFrame frame, Object value) {
// escape analysis should remove this allocation in compiled code
var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length];
// disallow power assertions from triggering in case one union member checks successfully
var localContext = VmLanguage.get(this).localContext.get();
var wasInTypeTest = localContext.isInTypeTest();
localContext.setInTypeTest(true);
for (var i = 0; i < elementTypeNodes.length; i++) {
// eager checks
try {
var result = elementTypeNodes[i].executeEagerly(frame, value);
localContext.setInTypeTest(wasInTypeTest);
return result;View on GitHub (pinned to f3efcbfc9b)
Solutions
- Fix the value so it matches one of the union's members (check the per-member messages in the error output).
- Widen the union type in the schema to include the value's actual type (e.g. add `Null` if the value can be absent).
- If the value comes from an external source, coerce or validate it before feeding it to the module.
- Check for typos in string-literal union members.
Example fix
// before name: "dev" | "prod" | "staging" // config sets name = "Prod" // after name: "dev" | "prod" | "staging" // config sets name = "prod"
Defensive patterns
Strategy: validation
Validate before calling
// Pkl: guard before assigning to a union-typed property
function checkName(v: String): String =
if (v == "dev" || v == "prod" || v == "staging") v
else throw("name must be one of dev|prod|staging, got: \(v)") Type guard
// Pkl type test x is Int | String
Prevention
- Test modules with `pkl test` covering each union member and a negative case.
- Avoid overly wide unions; validate external input at the module boundary.
- Read the per-member sub-errors in the message to find the nearest match.
When it happens
Trigger: A property/type-alias/type-argument annotated with a union type receives a value that fails every member's type check, e.g. a property `x: Int|String` assigned `true`, or `Listing<Int>|Listing<String>` given elements of neither element type. Raised lazily (executeLazily) or eagerly depending on member types.
Common situations: Config values coming from external sources (CLI flags, environment substitution, rendered/amend values) whose inferred Pkl value is not one of the declared union alternatives; typos in string-literal unions; widening a property's union type without updating all importing modules.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- VmTypeMismatchException.Union (type mismatch for union type)
- Error converting property `%s` in Pkl object of type `%s` to
- The top-level value of a YAML stream must have type `Collect
- type constraint mismatch
- type mismatch
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/1e2f892945d03d14.
Report an issue: GitHub.