apple/pkl · error · VmException

cannotIterateOverThisValue

cannotIterateOverThisValue

Error message

Cannot iterate over value of type `{0}`.

What it means

Pkl's `...` spread operator was applied to a value that evaluated to `null`, so the generator cannot iterate it. Pkl throws this instead of silently skipping the spread. The error suggests using `...?` (nullable spread) which skips null values.

Solutions

  1. Use the nullable spread operator `...?` instead of `...` to skip null values.
  2. Guard the value before spreading: `...(options ?? [])`.
  3. Fix the upstream expression so it returns an empty List/Map instead of null.

Example fix

// before
foo {
  ...maybeNullList
}
// after
foo {
  ...?maybeNullList
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (maybeNull != null) { /* safe to spread */ }

Type guard

function isSpreadable(v) { return v != null && (v is List || v is Map || v is Set || v is IntSeq); }

Try / catch

Use `...?expr` so null is skipped rather than thrown.

Prevention

When it happens

Trigger: Using `...expr` inside an object literal where `expr` evaluates to `null` (e.g. a property that is null, an external value, or a conditional that produced nothing).

Common situations: Config files where an optional external input (env var, CLI argument, imported property) is null and is spread into a Dynamic/Listing: `...options` where `options = null`.

Related errors


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

Appendix: source

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

    this.nullable = nullable;
  }

  protected abstract void executeWithIterable(
      VirtualFrame frame, Object parent, ObjectData data, Object iterable);

  @Override
  public final void execute(VirtualFrame frame, Object parent, ObjectData data) {
    executeWithIterable(frame, parent, data, iterableNode.executeGeneric(frame));
  }

  @Specialization
  @SuppressWarnings("unused")
  protected void eval(VmObject parent, ObjectData data, VmNull iterable) {
    if (nullable) {
      return;
    }
    CompilerDirectives.transferToInterpreter();
    throw exceptionBuilder()
        .evalError("cannotIterateOverThisValue", BaseModule.getNullClass())
        .withLocation(iterableNode)
        .withHint(
            "To guard against a nullable value, use `...?` instead of `...`.\n"
                + "Try: `...?"
                + iterableNode.getSourceSection().getCharacters()
                + "`")
        .build();
  }

  @Specialization(guards = "!iterable.isTyped()")
  @SuppressWarnings("unused")
  protected void eval(VirtualFrame frame, VmDynamic parent, ObjectData data, VmObject iterable) {
    doEvalDynamic(frame, data, iterable);
  }

  @Specialization(guards = "!iterable.isTyped()")
  @SuppressWarnings("unused")

View on GitHub (pinned to f3efcbfc9b)