{"record":{"id":"1cda57cccc4b1e9f","repo":"apple/pkl","slug":"type-mismatch-value-s-class-differs-from-expected","errorCode":null,"errorMessage":"type mismatch: value's class differs from expected class","messagePattern":"type mismatch: value's class differs from expected class","errorType":"exception","errorClass":"VmTypeMismatchException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java","lineNumber":724,"sourceCode":"  /**\n   * A non-open and non-abstract class type. Since this node is not used for\n   * String/Boolean/Int/Float and their supertypes, only `VmValue`s can possibly pass its type\n   * check.\n   */\n  public static final class FinalClassTypeNode extends ObjectSlotTypeNode\n      implements UserClassTypeNode {\n    private final VmClass clazz;\n\n    public FinalClassTypeNode(SourceSection sourceSection, VmClass clazz) {\n      super(sourceSection);\n      this.clazz = clazz;\n    }\n\n    @Override\n    protected Object executeLazily(VirtualFrame frame, Object value) {\n      if (value instanceof VmValue vmValue && clazz == vmValue.getVmClass()) return value;\n\n      throw typeMismatch(value, clazz);\n    }\n\n    @Override\n    public VmClass getVmClass() {\n      return clazz;\n    }\n\n    @Override\n    public VmList getTypeArgumentMirrors() {\n      // `List<X>` is represented by `ListTypeNode`,\n      // but `List` is represented by `FinalClassTypeNode`\n      return createUnknownTypeArgumentMirrors(clazz);\n    }\n\n    @Override\n    public @Nullable Object createDefaultValue(\n        VirtualFrame frame,\n        VmLanguage language,","sourceCodeStart":706,"sourceCodeEnd":742,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java#L706-L742","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Convert the value to the exact expected class (e.g. `value.toInt()`, `value.toList()`, `Double(...)`).","If several classes are acceptable, declare a union type (`Int | Float`).","Check the declared type at the error position and make the producer return that exact class.","Avoid implicit numeric widening assumptions — Pkl does not coerce between number classes."],"exampleFix":"// before\nx: Int = 1.5\n// after\nx: Int = 1.5.toInt()   // or declare `x: Float`","handlingStrategy":"type-guard","validationCode":"// Pkl\nif (value is Int) { x: Int = value } else if (value is Float) { x: Int = value.toInt() }","typeGuard":"function isExactInt(value: Any): Boolean = value is Int","tryCatchPattern":"// Convert explicitly (toInt()/toList()/etc.) before assignment; embedders: catch PklException with 'class differs from expected class'.","preventionTips":["Pkl never coerces between final classes — always convert explicitly","Watch numeric literals: 1 vs 1.0 are different classes","Declare union types when sibling classes are acceptable"],"tags":["pkl","type-mismatch","final-class","typecheck"],"backgroundTag":"type-mismatch","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}