apple/pkl · error

commandOptionsTypeAbstractClass

commandOptionsTypeAbstractClass

Error message

commandOptionsTypeAbstractClass

What it means

getOptionsClass throws commandOptionsTypeAbstractClass when the class given as a command's `options` type is abstract. Abstract classes have no instantiable properties to parse flags from, so the CLI spec parser rejects them at the class header section.

Source

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

      // at this point we've asserted the options property exists and that it is neither amended nor
      // assigned
      // the only possibility here is that it has a type annotation, otherwise this wouldn't parse
      throw PklBugException.unreachableCode();
    }
    var optionsTypeNode = optionsPropertyTypeNode.getTypeNode();
    if (optionsTypeNode instanceof TypeNode.TypedTypeNode) {
      return BaseModule.getTypedClass();
    }
    if (!(optionsTypeNode instanceof TypeNode.UserClassTypeNode node)) {
      throw exceptionBuilder()
          .withSourceSection(optionsTypeNode.getSourceSection())
          .evalError(
              "commandOptionsTypeNotClass", optionsTypeNode.getSourceSection().getCharacters())
          .build();
    }
    var clazz = node.getVmClass();
    if (clazz.isAbstract()) {
      throw exceptionBuilder()
          .withSourceSection(clazz.getHeaderSection())
          .evalError("commandOptionsTypeAbstractClass", clazz.getQualifiedName())
          .build();
    }
    return clazz;
  }

  private Iterable<CommandSpec.Option> collectOptions(VmClass optionsClass) {
    CommandSpec.Argument lastRepeatedArg = null;
    EconomicMap<String, CommandSpec.Option> opts = EconomicMap.create();

    var clazz = optionsClass;
    while (clazz != null) {
      for (var prop : clazz.getDeclaredProperties()) {
        var name = prop.getName().toString();
        if (VmModifier.isLocalOrExternalOrAbstractOrFixedOrConst(prop.getModifiers())
            || opts.containsKey(name)) continue;

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Remove `abstract` from the options class
  2. Create a concrete subclass of the abstract base and use that as the `options` type
  3. Move shared fields into the abstract base but declare concrete options classes per command

Example fix

// before
abstract class Options { verbose: Boolean }
options: Options
// after
class Options extends BaseOptions { ... }
options: Options
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the options class is instantiable
// abstract class Options { ... }  <-- invalid
// class Options extends BaseOpts { ... }  <-- valid

Type guard

function isConcreteClass(c) { return c && !c.isAbstract; }

Prevention

When it happens

Trigger: Declaring `abstract class Options { ... }` and using it as the `options` type of a CLI command.

Common situations: Factoring shared options into an abstract base class and forgetting to make the concrete per-command options class; converting an options class to abstract during refactoring.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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