apple/pkl · error · VmTypeMismatchException

type mismatch: value is not of type String

Error message

type mismatch: value is not of type String

What it means

The String typecheck node's executeLazily accepts a value only if it is a Java String (Pkl String); anything else fails with 'type mismatch: value is not of type String' via typeMismatch(value, BaseModule.getStringClass()). Pkl does not coerce numbers/booleans to strings implicitly.

Source

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

      return other instanceof AnyTypeNode;
    }

    @Override
    protected boolean acceptTypeNode(boolean visitTypeArguments, TypeNodeConsumer consumer) {
      return consumer.accept(this);
    }
  }

  public static final class StringTypeNode extends ObjectSlotTypeNode {
    public StringTypeNode(SourceSection sourceSection) {
      super(sourceSection);
    }

    @Override
    protected Object executeLazily(VirtualFrame frame, Object value) {
      if (value instanceof String) return value;

      throw typeMismatch(value, BaseModule.getStringClass());
    }

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

    @Override
    public boolean doIsEquivalentTo(TypeNode other) {
      return other instanceof StringTypeNode;
    }

    @Override
    protected boolean acceptTypeNode(boolean visitTypeArguments, TypeNodeConsumer consumer) {
      return consumer.accept(this);
    }
  }

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Convert explicitly with `.toString()` or string interpolation `"\(value)"`
  2. Fix the source value to be a string (quote it in the imported data)
  3. Relax the declaration type if a non-string is legitimate (e.g. `String|Int`)
  4. Validate with `v is String` before assignment

Example fix

// before
name: String = 42
// after
name: String = "42"
// or
name: String|Int = 42
Defensive patterns

Strategy: validation

Validate before calling

// pkl: assert(value is String)
function isString(v) { return typeof v === 'string'; }

Type guard

function isString(v) { return typeof v === 'string'; }

Try / catch

try { checkString(value); } catch (e) { log(`expected String, got ${typeof value}: ${value}`); throw e; }

Prevention

When it happens

Trigger: Assigning a number, Boolean, null, or object to a property typed String, e.g. `name: String = 42` or an imported JSON field that is a number.

Common situations: JSON/YAML imports where a field is sometimes numeric (`port: 8080`); interpolation forgotten (using `x` instead of `"\(x)"`); env-var substitution yielding null.

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/032eb5766d790ec7. Report an issue: GitHub.