apple/pkl · error · VmException

cannotSpreadObject

cannotSpreadObject

Error message

Cannot spread value of type `{0}` into object of type `{1}`.

What it means

A `List` or `Set` was spread with `...` into a typed object or a `Mapping`. List/Set spreads add elements, which only `Dynamic` and `Listing` objects accept. Pkl rejects the spread at evaluation time.

Solutions

  1. Spread the List/Set into a `Dynamic` or `Listing` object instead.
  2. Convert the collection to a Map and spread into a `Mapping`: `...Map.from(list)` is not valid; instead use element syntax appropriate for the target type.
  3. Remove the spread and assign properties/elements explicitly.

Example fix

// before
new Server {
  ...[8080, 9090] // List into typed object
}
// after
new Listing<Int> {
  ...[8080, 9090]
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure target is Dynamic/Listing before spreading List/Set
assert(isDynamic(target) || target is Listing)

Type guard

function canSpreadElements(target) { return target is Dynamic || target is Listing; }

Prevention

When it happens

Trigger: `...someList` or `...someSet` inside a `new Foo { ... }` (typed object) body, or inside a `Mapping { ... }` body.

Common situations: Spreading default element lists into a typed schema object or a Mapping, e.g. `server { ...commonPorts }` where `server` is a typed class or Mapping.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorSpreadNode.java:242

  private void doEvalTyped(VirtualFrame frame, VmClass clazz, ObjectData data, VmObject iterable) {
    iterable.forceAndIterateMemberValues(
        (key, member, value) -> {
          if (member.isElement() || member.isEntry()) {
            cannotHaveMember(clazz, member);
          }
          checkIsValidTypedProperty(clazz, member);
          data.addProperty(frame, createMember(member, value), this);
          return true;
        });
  }

  // handles both `List` and `Set`
  private void doEvalCollection(
      VirtualFrame frame, VmClass parent, ObjectData data, VmCollection iterable) {
    if (isTypedObjectClass(parent) || parent == getMappingClass()) {
      CompilerDirectives.transferToInterpreter();
      throw exceptionBuilder()
          .evalError("cannotSpreadObject", iterable.getVmClass(), parent)
          .withHint(
              "`List` and `Set` can only be spread into objects of type `Dynamic` and `Listing`.")
          .withProgramValue("Value", iterable)
          .build();
    }
    spreadIterable(frame, data, iterable);
  }

  private void doEvalMap(VirtualFrame frame, VmClass parent, ObjectData data, VmMap iterable) {
    if (isTypedObjectClass(parent) || parent == getListingClass()) {
      CompilerDirectives.transferToInterpreter();
      throw exceptionBuilder()
          .evalError("cannotSpreadObject", iterable.getVmClass(), parent)
          .withHint("`Map` can only be spread into objects of type `Dynamic` and `Mapping`.")
          .withProgramValue("Value", iterable)
          .build();
    }

View on GitHub (pinned to f3efcbfc9b)