apple/pkl · error · VmTypeMismatchException

type mismatch: value is not of type Pair

Error message

type mismatch: value is not of type Pair

What it means

Thrown by PairTypeNode.executeLazily when a lazily-checked value is not a VmPair. The node first typechecks both components of a Pair against its element types; a non-Pair value falls through to this error.

Solutions

  1. Construct a real Pair with `Pair(first, second)` instead of a list/tuple-like value.
  2. Verify the value is not null or a differently-shaped collection.
  3. If the annotation should accept a list, change the type to `Listing`/`List` accordingly.
  4. Trace the failing property's annotation and align value construction with `Pair(a, b)`.

Example fix

// before
p: Pair<Int, Int> = List(1, 2)

// after
p: Pair<Int, Int> = Pair(1, 2)
Defensive patterns

Strategy: validation

Validate before calling

if (value is Pair) { /* ok */ } else { throw "expected Pair" }

Type guard

function isPair(v: Any): Boolean = v is Pair

Prevention

When it happens

Trigger: A value annotated `Pair<X, Y>` receives something that is not a pkl Pair (e.g. a List, Listing, Int, or null) during lazy (speculative/slow-path) evaluation.

Common situations: Using stdlib Pair types in annotations and assigning a two-element Listing or List literal; passing tuples from other languages; building config where a Pair is expected but an array-like value was written.

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/451957908486979c. Report an issue: GitHub.

Appendix: source

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

    public PairTypeNode(
        SourceSection sourceSection, TypeNode firstTypeNode, TypeNode secondTypeNode) {
      super(sourceSection);
      this.firstTypeNode = firstTypeNode;
      this.secondTypeNode = secondTypeNode;
    }

    @Override
    protected Object executeLazily(VirtualFrame frame, Object value) {
      if (value instanceof VmPair vmPair) {
        var first = firstTypeNode.executeLazily(frame, vmPair.getFirst());
        var second = secondTypeNode.executeLazily(frame, vmPair.getSecond());
        if (first == vmPair.getFirst() && second == vmPair.getSecond()) {
          return vmPair;
        }
        return new VmPair(first, second);
      }
      throw typeMismatch(value, BaseModule.getPairClass());
    }

    @Override
    public Object executeEagerly(VirtualFrame frame, Object value) {
      if (value instanceof VmPair vmPair) {
        firstTypeNode.executeEagerly(frame, vmPair.getFirst());
        secondTypeNode.executeEagerly(frame, vmPair.getSecond());
        return value;
      }
      throw typeMismatch(value, BaseModule.getPairClass());
    }

    @Override
    public VmClass getVmClass() {
      return BaseModule.getPairClass();
    }

    @Override

View on GitHub (pinned to f3efcbfc9b)