apple/pkl · error · GenericParserError

typeAnnotationInAmends

typeAnnotationInAmends

Error message

Properties with type annotations cannot have object bodies.

What it means

A class property declared with a type annotation (`name: Type`) was followed by an object (amends) body `{ ... }`. The Pkl grammar forbids combining a type annotation with an amends body in a class property, so the parser rejects it.

Solutions

  1. Remove the type annotation if the property should amend another object (`foo { ... }`)
  2. Remove the amends body and give a typed default value instead (`foo: String = "h"`)
  3. Declare the base type in the amends target, not on the property

Example fix

// before
foo: String { host = "x" }
// after
foo {
  host = "x"
}
// or
foo: String = "x"
Defensive patterns

Strategy: validation

Validate before calling

/^\s*\w+\s*:\s*[A-Z][\w.]*(\s*\{)/.test(source) // flags typed property followed by '{' — refactor before parsing

Try / catch

try { parser.parse(src) } catch (e) {
  if (String(e.message).includes('type annotations cannot have object bodies')) {
    throw new SyntaxError('Remove the type annotation or the { ... } body on the class property');
  }
  throw e;
}

Prevention

When it happens

Trigger: parseClassProperty sees `lookahead() == Token.LBRACE` after a property that `hasTypeAnnotation`, e.g. `foo: String { ... }` inside a class or module.

Common situations: Mixing Java/TypeScript-style typed syntax with Pkl amends syntax; intending a default value and accidentally writing an amends block; copying an object-literal pattern into a class property.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at pkl-parser/src/main/java/org/pkl/parser/GenericParserImpl.java:326

    headerBegin.add(parseIdentifier());
    header.add(new Node(NodeType.CLASS_PROPERTY_HEADER_BEGIN, headerBegin));
    var hasTypeAnnotation = false;
    if (lookahead() == Token.COLON) {
      ff(header);
      header.add(parseTypeAnnotation());
      hasTypeAnnotation = true;
    }
    children.add(new Node(NodeType.CLASS_PROPERTY_HEADER, header));
    if (lookahead() == Token.ASSIGN) {
      ff(children);
      children.add(makeTerminal(next()));
      var body = new ArrayList<Node>();
      ff(body);
      body.add(parseExpr());
      children.add(new Node(NodeType.CLASS_PROPERTY_BODY, body));
    } else if (lookahead() == Token.LBRACE) {
      if (hasTypeAnnotation) {
        throw parserError("typeAnnotationInAmends");
      }
      while (lookahead() == Token.LBRACE) {
        ff(children);
        children.add(parseObjectBody());
      }
    }
    return new Node(NodeType.CLASS_PROPERTY, children);
  }

  private Node parseClassMethod(List<Node> preChildren) {
    var headerParts = getHeaderParts(preChildren);
    var children = new ArrayList<>(headerParts.preffixes);
    var headers = new ArrayList<Node>();
    if (headerParts.modifierList != null) {
      headers.add(headerParts.modifierList);
    }
    expect(Token.FUNCTION, headers, "unexpectedToken", "function");
    ff(headers);

View on GitHub (pinned to f3efcbfc9b)