{"record":{"id":"12f62ea26868a4fb","repo":"apple/pkl","slug":"commandoptionstypenotclass","errorCode":"commandOptionsTypeNotClass","errorMessage":"commandOptionsTypeNotClass","messagePattern":"commandOptionsTypeNotClass","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java","lineNumber":177,"sourceCode":"  private VmClass getOptionsClass(VmTyped command) {\n    var optionsProperty = command.getVmClass().getProperty(Identifier.OPTIONS);\n    if (optionsProperty == null) {\n      // at this point we've asserted the command extends pkl:Command\n      throw PklBugException.unreachableCode();\n    }\n    var optionsPropertyTypeNode = optionsProperty.getTypeNode();\n    if (optionsPropertyTypeNode == null) {\n      // at this point we've asserted the options property exists and that it is neither amended nor\n      // assigned\n      // the only possibility here is that it has a type annotation, otherwise this wouldn't parse\n      throw PklBugException.unreachableCode();\n    }\n    var optionsTypeNode = optionsPropertyTypeNode.getTypeNode();\n    if (optionsTypeNode instanceof TypeNode.TypedTypeNode) {\n      return BaseModule.getTypedClass();\n    }\n    if (!(optionsTypeNode instanceof TypeNode.UserClassTypeNode node)) {\n      throw exceptionBuilder()\n          .withSourceSection(optionsTypeNode.getSourceSection())\n          .evalError(\n              \"commandOptionsTypeNotClass\", optionsTypeNode.getSourceSection().getCharacters())\n          .build();\n    }\n    var clazz = node.getVmClass();\n    if (clazz.isAbstract()) {\n      throw exceptionBuilder()\n          .withSourceSection(clazz.getHeaderSection())\n          .evalError(\"commandOptionsTypeAbstractClass\", clazz.getQualifiedName())\n          .build();\n    }\n    return clazz;\n  }\n\n  private Iterable<CommandSpec.Option> collectOptions(VmClass optionsClass) {\n    CommandSpec.Argument lastRepeatedArg = null;\n    EconomicMap<String, CommandSpec.Option> opts = EconomicMap.create();","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java#L159-L195","documentation":"getOptionsClass throws commandOptionsTypeNotClass when a command's `options` property is not typed as a plain user class. Only a concrete user class (or the Base `Typed` class) is supported for CLI options; unions, aliases, constrained types, strings, etc. are rejected, with the offending type's source text in the message.","triggerScenarios":"Declaring `options: String` or `options: A|B` or `options: A(n: 1)` — the options property's type node is not a TypeNode.UserClassTypeNode (nor TypedTypeNode).","commonSituations":"Typing options as an interface/union/alias instead of a class; using a constrained type like `options: Options/*.foo = 1*/`; accidentally pointing options at a non-class module member.","solutions":["Define `options` as a plain (non-abstract) class and type the property with it","Remove unions, constraints, type aliases, or intersections from the options type","Check that the referenced name resolves to a class, not a module property or function"],"exampleFix":"// before\noptions: String\n// after\nclass Options { ... }\noptions: Options","handlingStrategy":"type-guard","validationCode":"// pkl-side check before wiring CLI\nclass Options { ... }\noptions: Options // must be a plain class type","typeGuard":"function isPlainClassType(t) { return t && !t.union && !t.constraint && !t.alias && typeof t === \"class\"; }","tryCatchPattern":null,"preventionTips":["Always define a dedicated concrete options class per command","Avoid unions/aliases/constraints on the options property","Confirm the referenced identifier is a class, not a module property"],"tags":["pkl","cli","command-spec","types"],"backgroundTag":"type-mismatch","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}