apple/pkl · warning · PrintHelpMessage

<prints command help and exits with code 1>

Error message

<prints command help and exits with code 1>

What it means

When a command that only dispatches to subcommands is invoked without choosing a subcommand, run() throws PrintHelpMessage(currentContext, true, 1): the CLI prints the command's help text and exits with status code 1. It is a controlled error, not a crash — the library uses it to tell the user which subcommands exist.

Solutions

  1. Specify a subcommand, e.g. `pkl eval ...` or `pkl test ...`
  2. Run `pkl --help` (or `<command> --help`) to list available subcommands
  3. Fix script/alias that omitted the subcommand name

Example fix

// before
pkl
// after
pkl eval script.pkl
Defensive patterns

Strategy: fallback

Validate before calling

// only proceed when a subcommand is present
if [ $# -eq 0 ]; then echo "usage: pkl <subcommand> ..."; exit 1; fi

Try / catch

// PrintHelpMessage is control flow: catch and treat exit code 1 as usage help
try { cmd.execute(args) }
catch (e: PrintHelpMessage) { print(e.helpText); exitProcess(1) }

Prevention

When it happens

Trigger: Invoking a group command with noOp=true and non-empty subcommands without specifying any subcommand, e.g. `pkl` with no verb, or `pkl project` alone; spec.apply succeeds but invokedSubcommand is null.

Common situations: Running the bare command in scripts expecting default behavior; typo in the subcommand name so no subcommand was matched; users exploring the CLI interactively.

Understand the failure class

Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.

Related errors


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

Appendix: source

Thrown at pkl-cli/src/main/kotlin/org/pkl/cli/CliCommandRunner.kt:255

      val opts =
        registeredOptions()
          .mapNotNull {
            val opt = it as? OptionWithValues<*, *, *> ?: return@mapNotNull null
            return@mapNotNull if (it.names.contains("--help")) null
            else it.names.last().trimStart('-') to opt.value
          }
          .toMap() +
          registeredArguments()
            .mapNotNull { it as? ArgumentDelegate<*> }
            .associateBy({ it.name }, { it.value })

      val state = spec.apply.apply(opts, currentContext.obj as CommandSpec.State?)
      currentContext.obj = state

      if (currentContext.invokedSubcommand != null) return
      if (spec.subcommands.isNotEmpty() && spec.noOp) {
        throw PrintHelpMessage(currentContext, true, 1)
      }

      val result = state.evaluate()
      runner.writeOutput(result.outputBytes)
      runner.writeMultipleFileOutput(result.outputFiles)
    }
  }
}

fun CommandSpec.CompletionCandidates.toClikt(): CompletionCandidates =
  when (this) {
    CommandSpec.CompletionCandidates.PATH -> CompletionCandidates.Path
    is CommandSpec.CompletionCandidates.Fixed -> CompletionCandidates.Fixed(values)
    else -> throw PklBugException.unreachableCode()
  }

View on GitHub (pinned to f3efcbfc9b)