apple/pkl · error · VmException
objectCannotHavePredicateMember
objectCannotHavePredicateMember
Error message
Object of type `{0}` cannot have a predicate member. What it means
Predicate members (`when (cond) { ... }` / `whenDefined`) are only allowed on Dynamic, Listing, and Mapping objects. Applying a predicate member to any other object type (a typed class instance, Number, etc.) is rejected with the offending type named.
Solutions
- Move the conditional logic outside the object: compute values with `if` expressions on properties instead of `when` members.
- For typed classes, conditionally include properties via `default`-value expressions or by building a Dynamic in the amender and converting.
- Confirm the amended type is Dynamic, Listing, or Mapping before using predicate members.
Example fix
// before
server {
when (env == "dev") { replicas = 1 }
}
// after
server {
replicas = if (env == "dev") 1 else 3
} Defensive patterns
Strategy: type-guard
Validate before calling
// Only use `when` members if the parent is Dynamic/Listing/Mapping
when (parent is Dynamic || parent is Listing || parent is Mapping) {
// predicate member allowed here
} Type guard
function supportsPredicateMembers(v: Any): Boolean = v is Dynamic || v is Listing || v is Mapping
Prevention
- Use `if` expressions on property values for typed classes instead of `when` members.
- Restrict `when` usage to Dynamic/Listing/Mapping bodies.
- Keep conditional logic in computed properties for typed schemas.
When it happens
Trigger: Declaring `when (...) { ... }` inside an amendment of an object whose type is not Dynamic/Listing/Mapping — e.g. amending an instance of a typed Pkl class or a base value. Raised in the public fallback of GeneratorPredicateMemberNode when the parent isn't the allowed parent classes.
Common situations: Adding `when` blocks inside typed class amendments to conditionally set properties; adding predicate members to List/List-like values; using `when` in a module-level `amends` of a typed schema class.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- objectCannotHaveProperty
- typeMismatch
- abstractMemberCannotHaveBody
- abstractMethodInNonAbstractType
- array
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/118829dfc582f602.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorPredicateMemberNode.java:72
@Specialization
@SuppressWarnings("unused")
protected void evalListing(VirtualFrame frame, VmListing parent, ObjectData data) {
addMembers(frame, parent, data);
}
@Fallback
@SuppressWarnings("unused")
void fallback(Object parent, ObjectData data) {
if (parent == BaseModule.getDynamicClass()
|| parent == BaseModule.getMappingClass()
|| parent == BaseModule.getListingClass()) {
// nothing to do (parent is guaranteed to have zero elements/entries)
return;
}
CompilerDirectives.transferToInterpreter();
throw exceptionBuilder()
.evalError(
"objectCannotHavePredicateMember",
parent instanceof VmClass ? parent : VmUtils.getClass(parent))
.withLocation(predicateNode)
.build();
}
private void addMembers(VirtualFrame frame, VmObject parent, ObjectData data) {
initThisSlot(frame);
var previousValue = frame.getAuxiliarySlot(customThisSlot);
var visitedKeys = EconomicSets.create();
// do our own traversal instead of relying on `VmAbstractObject.force/iterateMemberValues`
// (more efficient and we don't want to execute `predicateNode` behind Truffle boundary)
for (var owner = parent; owner != null; owner = owner.getParent()) {
var entries = EconomicMaps.getEntries(owner.getMembers());
while (entries.advance()) {View on GitHub (pinned to f3efcbfc9b)