apple/pkl · error · VmTypeMismatchException

type mismatch: value's class differs from expected class

Error message

type mismatch: value's class differs from expected class

What it means

Pkl exact-class type check failure. This node checks `clazz == vmValue.getVmClass()` — the value's class must be exactly the expected final class (no subclassing allowed, because the class is final). The value was a VmValue but its runtime class differed from the expected one.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java:724

  /**
   * A non-open and non-abstract class type. Since this node is not used for
   * String/Boolean/Int/Float and their supertypes, only `VmValue`s can possibly pass its type
   * check.
   */
  public static final class FinalClassTypeNode extends ObjectSlotTypeNode
      implements UserClassTypeNode {
    private final VmClass clazz;

    public FinalClassTypeNode(SourceSection sourceSection, VmClass clazz) {
      super(sourceSection);
      this.clazz = clazz;
    }

    @Override
    protected Object executeLazily(VirtualFrame frame, Object value) {
      if (value instanceof VmValue vmValue && clazz == vmValue.getVmClass()) return value;

      throw typeMismatch(value, clazz);
    }

    @Override
    public VmClass getVmClass() {
      return clazz;
    }

    @Override
    public VmList getTypeArgumentMirrors() {
      // `List<X>` is represented by `ListTypeNode`,
      // but `List` is represented by `FinalClassTypeNode`
      return createUnknownTypeArgumentMirrors(clazz);
    }

    @Override
    public @Nullable Object createDefaultValue(
        VirtualFrame frame,
        VmLanguage language,

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Convert the value to the exact expected class (e.g. `value.toInt()`, `value.toList()`, `Double(...)`).
  2. If several classes are acceptable, declare a union type (`Int | Float`).
  3. Check the declared type at the error position and make the producer return that exact class.
  4. Avoid implicit numeric widening assumptions — Pkl does not coerce between number classes.

Example fix

// before
x: Int = 1.5
// after
x: Int = 1.5.toInt()   // or declare `x: Float`
Defensive patterns

Strategy: type-guard

Validate before calling

// Pkl
if (value is Int) { x: Int = value } else if (value is Float) { x: Int = value.toInt() }

Type guard

function isExactInt(value: Any): Boolean = value is Int

Try / catch

// Convert explicitly (toInt()/toList()/etc.) before assignment; embedders: catch PklException with 'class differs from expected class'.

Prevention

When it happens

Trigger: Assigning an instance of a different (final) class than declared, e.g. declaring `IntSeq`-like or other final VmValue class types (Int8/UInt16/List/etc.) and passing a sibling type such as assigning an `Int` where `Int32`... class-exact types are enforced; passing a Float where Int is required.

Common situations: Numeric type confusion (Int vs Float, Int8 vs Int), passing a List where a Set (or similar final collection class) is declared, or declaring a concrete final class and receiving a subclass/other class instance from a library.

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


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/1cda57cccc4b1e9f. Report an issue: GitHub.