apple/pkl · error · VmException
forWhenBodyCannotHaveParameters
forWhenBodyCannotHaveParameters
Error message
forWhenBodyCannotHaveParameters
What it means
In `for`/`when` generator expressions, the body object cannot declare parameters — the iteration variables are already bound by the `for` clause. If the body's parameter list is non-empty, doVisitForWhenBody throws forWhenBodyCannotHaveParameters, pointing at the first parameter.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/builder/AstBuilder.java:1548
@Override
public GeneratorMemberNode visitWhenGenerator(WhenGenerator member) {
var sourceSection = createSourceSection(member);
var thenNodes = doVisitForWhenBody(member.getThenClause());
var elseNodes =
member.getElseClause() == null
? new GeneratorMemberNode[0]
: doVisitForWhenBody(member.getElseClause());
// when predicates cannot see their direct scope
var predicateNode =
symbolTable.enterEagerGenerator((scope) -> visitExpr(member.getPredicate()));
return new GeneratorWhenNode(sourceSection, predicateNode, thenNodes, elseNodes);
}
private GeneratorMemberNode[] doVisitForWhenBody(ObjectBody body) {
if (!body.getParameters().isEmpty()) {
throw exceptionBuilder()
.evalError("forWhenBodyCannotHaveParameters")
.withSourceSection(createSourceSection(body.getParameters().get(0)))
.build();
}
return doVisitGeneratorMemberNodes(body.getMembers());
}
private @Nullable FrameSlotVariable makeBinding(
org.pkl.parser.syntax.@Nullable Parameter parameter) {
if (!(parameter instanceof TypedIdentifier typedIdentifier)) {
return null;
}
var name = typedIdentifier.getIdentifier().getValue();
return symbolTable
.getCurrentScope()
.frameDescriptorBuilder
.addSlot(FrameSlotKind.Illegal, toIdentifier(name), null);
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Remove the parameter list from the when body object.
- Access needed values through the for-bound variables or captures instead of parameters.
- If parameterization is required, use a plain function or a different construct than for/when generators.
Example fix
// before
for (x in xs) when (x > 0) (y) { emit(x) }
// after
for (x in xs) when (x > 0) { emit(x) } Defensive patterns
Strategy: validation
Validate before calling
// Ensure generator when-bodies have no parameter list before rendering:
if (body.params && body.params.length > 0) throw new Error('for/when bodies cannot take parameters'); Prevention
- Never attach a parameter list to for/when generator bodies; use the for-bound variables.
- Keep generator body syntax distinct from class/function body syntax.
When it happens
Trigger: Writing `for (x in xs) when (cond) (y) { ... }` — supplying a parameter list on the body of a when-branch within a for-generator member.
Common situations: Confusing generator `when` bodies with class or function bodies that take parameters, or leftover syntax from refactoring a regular member into a generator.
Related errors
- cannotAnalyzeBecauseSyntaxError
- invalidTripleDotSyntax
- invalidTypeName
- unseparatedObjectMembers
- elementIndexOutOfRange
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/e7b4932dbf84e355.
Report an issue: GitHub.