apple/pkl · error · VmException

abstractMemberCannotHaveBody

abstractMemberCannotHaveBody

Error message

abstractMemberCannotHaveBody

What it means

Pkl throws this at build time (AstBuilder) when a class or object member is declared `abstract` but also has a body. Abstract members are placeholders that subclasses must implement; they cannot carry an implementation. The parser-built AST rejects this combination while visiting the member's header/body.

Source

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

    var annotations = doVisitAnnotations(entry.getAnnotations(), methodName);

    return symbolTable.enterMethod(
        methodName,
        getConstLevel(modifiers),
        bindings,
        descriptorBuilder,
        typeParameters,
        scope -> {
          ExpressionNode bodyNode;
          if (bodyContext != null) {
            if (VmModifier.isExternal(modifiers)) {
              throw exceptionBuilder()
                  .evalError("externalMemberCannotHaveBody")
                  .withSourceSection(headerSection)
                  .build();
            }
            if (VmModifier.isAbstract(modifiers)) {
              throw exceptionBuilder()
                  .evalError("abstractMemberCannotHaveBody")
                  .withSourceSection(headerSection)
                  .build();
            }
            bodyNode = visitExpr(bodyContext);
          } else {
            if (VmModifier.isExternal(modifiers)) {
              bodyNode =
                  externalMemberRegistry.getFunctionBody(
                      scope.getQualifiedName(), headerSection, paramCount);
              if (bodyNode instanceof LanguageAwareNode languageAwareNode) {
                languageAwareNode.initLanguage(language);
              }
            } else if (VmModifier.isAbstract(modifiers)) {
              bodyNode =
                  new CannotInvokeAbstractFunctionNode(headerSection, scope.getQualifiedName());
            } else {
              throw exceptionBuilder()

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Remove the `= body` / method body so the member is a pure abstract declaration.
  2. Or remove the `abstract` modifier if the member should keep its implementation.
  3. If the intent was a default that subclasses override, declare it normally (no modifier) instead of abstract.

Example fix

// before
abstract function endpoint(): String = "https://api.example.com"
// after
abstract function endpoint(): String
Defensive patterns

Strategy: validation

Validate before calling

// before compiling, scan member declarations
function hasAbstractWithBody(member) {
  return member.modifiers.includes('abstract') && member.body != null;
}
if (members.some(hasAbstractWithBody)) throw new Error('abstract member must not have a body');

Prevention

When it happens

Trigger: Declaring a member inside a class (Amends/ClassBody) with both the `abstract` modifier and a non-empty body, e.g. `abstract function foo(): Int = 1` or `abstract x: String = "a"`. The check fires in the branch where the body exists and `VmModifier.isAbstract(modifiers)` is true.

Common situations: Converting a concrete member to abstract (adding `abstract`) without deleting its body; copy-pasting a member and adding `abstract` to satisfy an overridden contract; misunderstanding Pkl's abstract semantics compared to Java interfaces.

Related errors


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