apple/pkl · error

redundantOpenModifier

redundantOpenModifier

Error message

redundantOpenModifier

What it means

`abstract` and `open` are mutually exclusive class modifiers in Pkl: `abstract` forbids instantiation, `open` allows external amendment. Combining them is contradictory, so AstBuilder throws `redundantOpenModifier` pointing at the OPEN modifier (AstBuilder.java:3030).

Source

Thrown at pkl-core/src/main/java/org/pkl/core/ast/builder/AstBuilder.java:3030

          .build();
    }

    if (VmModifier.isLocal(result) && VmModifier.isHidden(result)) {
      throw exceptionBuilder()
          .evalError("redundantHiddenModifier")
          .withSourceSection(createSourceSection(modifiers, ModifierValue.HIDDEN))
          .build();
    }

    if (VmModifier.isLocal(result) && VmModifier.isFixed(result)) {
      throw exceptionBuilder()
          .evalError("redundantFixedModifier")
          .withSourceSection(createSourceSection(modifiers, ModifierValue.FIXED))
          .build();
    }

    if (VmModifier.isAbstract(result) && VmModifier.isOpen(result)) {
      throw exceptionBuilder()
          .evalError("redundantOpenModifier")
          .withSourceSection(createSourceSection(modifiers, ModifierValue.OPEN))
          .build();
    }

    return result;
  }

  private UnresolvedTypeNode[] doVisitParameterTypes(ObjectBody body) {
    return doVisitParameterTypes(body.getParameters());
  }

  private UnresolvedTypeNode[] doVisitParameterTypes(ParameterList paramList) {
    return doVisitParameterTypes(paramList.getParameters());
  }

  private UnresolvedTypeNode[] doVisitParameterTypes(List<org.pkl.parser.syntax.Parameter> params) {
    var typeNodes = new UnresolvedTypeNode[params.size()];

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Decide semantics: keep `abstract` (instantiation forbidden, must extend) or `open` (amendable), not both.
  2. In Pkl classes are effectively open to amendments already; usually just remove `open` from the abstract class.
  3. Split into an abstract base and an open subclass if both behaviors are needed.

Example fix

// before
abstract open class Foo {}
// after
abstract class Foo {}
Defensive patterns

Strategy: validation

Validate before calling

if (/abstract\s+open\s+class|open\s+abstract\s+class/.test(pklSource)) {
  throw new Error("`abstract` and `open` are mutually exclusive class modifiers");
}

Prevention

When it happens

Trigger: Declaring `abstract open class Foo {}` in a module.

Common situations: Copying modifier lists from multiple class declarations; unclear whether a class should be extensible or abstract, so both modifiers were kept.

Related errors


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