apple/pkl · error · VmException
cannotIterateOverThisValue
cannotIterateOverThisValue
Error message
Cannot iterate over value of type `{0}`. What it means
Thrown when a generator's `for` expression tries to iterate a value that is not iterable (not a List, Set, Map, String, Listing, Mapping, etc.). The `@Fallback` node catches any value the specialized iterable nodes cannot handle and reports the value's type.
Solutions
- Check the type of the iterated expression; wrap scalars in a list (`[expr]`) if iteration over a single value is intended.
- Use the nullish/type check pattern: only iterate when the value is a collection (e.g. `person.names.toList()`).
- Inspect the 'Value' attached to the error message to see the actual runtime value and correct the expression.
Example fix
// before
for (tag in contact.tags) { ... } // tags may be a single String
// after
for (tag in contact.tags.toList()) { ... } Defensive patterns
Strategy: type-guard
Validate before calling
// Pkl: guard before iterating
when (value is List || value is Set || value is Listing) {
for (x in value) { ... }
} Type guard
function isIterable(v: Any): Boolean = v is List || v is Set || v is Map || v is Listing || v is Mapping || v is String
Prevention
- Check the property's declared/defaulted type before `for`-ing over it.
- Convert single values with `[v].toList()` when a scalar-or-collection union is possible.
- Use `v is Collection` style checks in `when` guards.
When it happens
Trigger: `for (x in expr)` where `expr` evaluates to a non-iterable value — e.g. an Int, Boolean, a class instance, or a module object instead of a collection. Raised in the `fallback` node of GeneratorForNode.
Common situations: Iterating over a property that is a scalar (`for (p in person.name)`); forgetting that a nullable or default value resolved to `null`/Int instead of a List; iterating a module or class reference instead of one of its collections.
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
- cannotExportValue
- cannotFlattenCollectionWithNonCollectionElement
- cannotSpreadObject
- double
- Error converting property
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/b8671c10621e6536.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorForNode.java:144
var length = iterable.getLength();
for (long key = 0, value = iterable.start; key < length; key++, value += iterable.step) {
executeIteration(frame, parent, data, key, value);
}
}
@Specialization
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmBytes iterable) {
long idx = 0;
for (var byt : iterable.getBytes()) {
executeIteration(frame, parent, data, idx++, (long) byt);
}
}
@Fallback
@SuppressWarnings("unused")
protected void fallback(VirtualFrame frame, Object parent, ObjectData data, Object iterable) {
CompilerDirectives.transferToInterpreter();
throw exceptionBuilder()
.evalError("cannotIterateOverThisValue", VmUtils.getClass(iterable))
.withLocation(iterableNode)
.withProgramValue("Value", iterable)
.build();
}
private void doEvalObject(VirtualFrame frame, VmObject iterable, Object parent, ObjectData data) {
iterable.forceAndIterateMemberValues(
(key, member, value) -> {
var convertedKey = member.isProp() ? key.toString() : key;
// TODO: Executing iteration behind a Truffle boundary is bad for performance.
// This and similar cases will be fixed in an upcoming PR that replaces method
// `(forceAnd)iterateMemberValues` with cursor-based external iterators.
executeIteration(frame, parent, data, convertedKey, value);
return true;
});
}
View on GitHub (pinned to f3efcbfc9b)