apple/pkl · error · BadValue

+e.getMessage()

Error message

+e.getMessage()

What it means

CommandSpecParser.handleBadValue wraps any Throwable from value conversion/transform functions into a BadValue whose message is a newline plus e.getMessage(). The reported message is therefore just the underlying exception's message, reformatted so it prints neatly under a CLI 'invalid value for <name>:' line. The real cause is whatever the user-provided convert/transform function threw.

Source

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

  // endregion
  // region dynamic import handling

  private static boolean isImport(VmTyped value) {
    return value.getVmClass() == CommandModule.getImportClass();
  }

  private static boolean isImport(Object value) {
    return value instanceof VmTyped vmTyped
        && vmTyped.getVmClass() == CommandModule.getImportClass();
  }

  // handle errors from convert/transformAll and correctly format them for the CLI
  private Object handleBadValue(Supplier<Object> f) {
    try {
      return handleErrors(f);
    } catch (Throwable e) {
      // add a newline so this prints nicely under "Error: invalid value for <name>:"
      throw new BadValue("\n" + e.getMessage());
    }
  }

  private <T> T handleErrors(Supplier<T> f) {
    try {
      return f.get();
    } catch (VmStackOverflowException e) {
      if (VmUtils.isPklBug(e)) {
        throw new VmExceptionBuilder()
            .bug("Stack overflow")
            .withCause(e.getCause())
            .build()
            .toPklException(frameTransformer, color);
      }
      throw e.toPklException(frameTransformer, color);
    } catch (VmException e) {
      throw e.toPklException(frameTransformer, color);
    } catch (Exception e) {

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Read the wrapped message under 'invalid value for <name>:' to identify the failing conversion.
  2. Fix or guard the convert/transformAll function in the command spec so invalid input yields a clear message.
  3. Add explicit input validation in the converter that throws a descriptive message instead of an incidental exception.

Example fix

// before
convert { it.toInt() } // NumberFormatException surfaces raw
// after
convert { it.toIntOrNull() ?: throw IllegalArgumentException("expected an integer, got: $it") }
Defensive patterns

Strategy: try-catch

Validate before calling

// inside a command spec converter
convert { v -> require(v.isNotBlank()) { "value must not be blank" }; v }

Try / catch

try {
  runConversion(value)
} catch (e: BadValue) {
  logger.error("invalid value for ${flagName}: ${e.message}")
}

Prevention

When it happens

Trigger: A CLI flag/option value fails conversion: the spec's convert or transformAll function throws (custom converters, parse failures) while parsing command-spec-based CLI arguments.

Common situations: Custom `convert { }` blocks in command specs throwing on bad user input; split() or toInt() style failures in transform functions; exceptions thrown by user-provided validation code inside a spec.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


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