apple/pkl · error · GenericParserError

multipleUnionDefaults

multipleUnionDefaults

Error message

A type union cannot have more than one default type.

What it means

Within one type union, at most one member may carry the default marker `*`. parseType tracks hasDefault; when a second `*` is seen while parsing union members, it throws multipleUnionDefaults. A union default must be unambiguous to be usable in Pkl's type inference and amending semantics.

Solutions

  1. Keep exactly one `*` member; remove `*` from all but the intended default.
  2. Decide which member should be the default and mark only that one.
  3. Search the union declaration for repeated `*` occurrences.

Example fix

// before
x: *"a"|*"b"

// after
x: *"a"|"b"
Defensive patterns

Strategy: validation

Validate before calling

// At most one `*` default marker per union
function singleUnionDefault(typeExpr) {
  return (typeExpr.match(/\*/g) || []).length <= 1;
}

Prevention

When it happens

Trigger: Writing a union like `*"a"|*"b"` where two members both start with `*`.

Common situations: Editing a union and accidentally duplicating the `*` prefix when adding a member; bulk-replacing types that each had their own default; macros/templating that prepend `*` to every member.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

    var first = parseTypeAtom(expectation);
    children.add(first);

    if (lookahead() != Token.UNION) {
      if (hasDefault) {
        //noinspection ConstantValue (NullAway needs this assertion, IntelliJ doesn't)
        assert start != null;
        throw parserError(ErrorMessages.create("notAUnion"), start.endWith(first.span));
      }
      return first;
    }

    while (lookahead() == Token.UNION) {
      ff(children);
      children.add(makeTerminal(next()));
      ff(children);
      if (lookahead == Token.STAR) {
        if (hasDefault) {
          throw parserError("multipleUnionDefaults");
        }
        children.add(makeTerminal(next()));
        ff(children);
        hasDefault = true;
      }
      var type = parseTypeAtom(expectation);
      children.add(type);
    }
    return new Node(NodeType.UNION_TYPE, children);
  }

  private Node parseTypeAtom(@Nullable String expectation) {
    var typ =
        switch (lookahead) {
          case UNKNOWN -> make(NodeType.UNKNOWN_TYPE, next().span);
          case NOTHING -> make(NodeType.NOTHING_TYPE, next().span);
          case MODULE -> make(NodeType.MODULE_TYPE, next().span);
          case THIS -> make(NodeType.THIS_TYPE, next().span);

View on GitHub (pinned to f3efcbfc9b)