apple/pkl · error

commandOptionUnsupportedType

commandOptionUnsupportedType

Error message

commandOptionUnsupportedType

What it means

Thrown when an option's declared type is a supported generic collection (Listing, Mapping, List, Set, Map, or Pair) given WITHOUT its required type arguments. The framework needs element/key/value types to know how to convert each CLI token, so bare `List<Int>` is fine but bare `List` (or `Listing`) is rejected, with a hint about how many type arguments are needed.

Solutions

  1. Add the type arguments, e.g. `List<String>` or `Mapping<String, Int>`
  2. For Listing/Mapping, parameterize them: `Listing<String>`, `Mapping<String, String>`
  3. Use Pair<A, B> with both type arguments for pair-typed options

Example fix

// before
@Option include: List

// after
@Option include: List<String>
Defensive patterns

Strategy: validation

Validate before calling

// static check: collection-typed options must be parameterized
function checkRawCollections(props: Listing<ClassProperty>): Listing<String> {
  props.filter((p) -> p.type != null && p.type.isRawCollection())
       .map((p) -> p.name)
}

Prevention

When it happens

Trigger: Declaring `@Option include: List` or `@Option headers: Mapping` — a FinalClassTypeNode for Listing/Mapping/List/Set/Map/Pair with no type arguments reaches OptionBehavior.resolve and fails the first commandOptionUnsupportedType branch.

Common situations: Using raw collection types in Pkl property declarations; older Pkl code where bare Listing was common; copy-pasted specs stripped of type args.

Related errors


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

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java:597

                    var builder = VmMap.builder();
                    values.forEach(
                        (entry) ->
                            builder.add(((VmPair) entry).getFirst(), ((VmPair) entry).getSecond()));
                    return builder.build();
                  };
      } else if (typeNode instanceof TypeNode.PairTypeNode pairTypeNode) {
        handleEntry(pairTypeNode.getFirstTypeNode(), pairTypeNode.getSecondTypeNode(), prop);
        if (all == null) all = this::allChooseLast;
        if (multiple == null) multiple = false;
      } else if (typeNode instanceof TypeNode.FinalClassTypeNode finalClassTypeNode
          && (finalClassTypeNode.getVmClass() == BaseModule.getListingClass()
              || finalClassTypeNode.getVmClass() == BaseModule.getMappingClass()
              || finalClassTypeNode.getVmClass() == BaseModule.getListClass()
              || finalClassTypeNode.getVmClass() == BaseModule.getSetClass()
              || finalClassTypeNode.getVmClass() == BaseModule.getMapClass()
              || finalClassTypeNode.getVmClass() == BaseModule.getPairClass())) {
        // if a supported type is provided without type arguments
        throw exceptionBuilder()
            .withSourceSection(prop.getHeaderSection())
            .evalError(
                "commandOptionUnsupportedType",
                prop.getName(),
                "",
                typeNode.getSourceSection().getCharacters())
            .withHint(
                finalClassTypeNode.getVmClass().getSimpleName()
                    + " options must provide "
                    + switch (finalClassTypeNode.getVmClass().getTypeParameterCount()) {
                      case 1 -> "one type argument.";
                      case 2 -> "two type arguments.";
                      default -> throw PklBugException.unreachableCode();
                    })
            .build();
      } else if (each == null && all == null) {
        // if another type and no transform functions are provided, that's an error
        throw exceptionBuilder()

View on GitHub (pinned to f3efcbfc9b)