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

  1. Move the conditional logic outside the object: compute values with `if` expressions on properties instead of `when` members.
  2. For typed classes, conditionally include properties via `default`-value expressions or by building a Dynamic in the amender and converting.
  3. 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

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


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)