kestra-io/kestra · error · IllegalArgumentException

Select option object must define a `value` field

Error message

Select option object must define a `value` field

What it means

Thrown by ValueOption.from() when deserializing a SELECT input option from a Map that has no 'value' key. Each select option MUST carry a value (the option's underlying selection value); the label is optional and defaults to the value. This IllegalArgumentException surfaces during flow parsing/validation when an options entry is a JSON object missing the required value field.

Source

Thrown at core/src/main/java/io/kestra/core/models/flows/input/ValueOption.java:41

 */
@Schema(
    description = "A select option. Accepts either a plain string (used as both label and value) or an object with `label` and `value` fields.",
    anyOf = { String.class, ValueOption.ValueOptionObject.class }
)
public record ValueOption(@NotNull String label, @NotNull String value) {

    @JsonCreator
    public static ValueOption from(Object raw) {
        if (raw == null) {
            return null;
        }
        if (raw instanceof ValueOption v) {
            return v;
        }
        if (raw instanceof Map<?, ?> map) {
            Object rawValue = map.get("value");
            if (rawValue == null) {
                throw new IllegalArgumentException("Select option object must define a `value` field");
            }
            Object rawLabel = map.containsKey("label") ? map.get("label") : rawValue;
            return new ValueOption(rawLabel.toString(), rawValue.toString());
        }
        String str = raw.toString();
        return new ValueOption(str, str);
    }

    @JsonValue
    public Object toJson() {
        if (Objects.equals(label, value)) {
            return value;
        }
        Map<String, String> map = new LinkedHashMap<>();
        map.put("label", label);
        map.put("value", value);
        return map;
    }

View on GitHub (pinned to 823fada927)

Solutions

  1. Ensure every object-form select option includes a 'value' field.
  2. Use the string shorthand (just the value) for label-less options: options: [a, b, c].
  3. Validate the flow YAML/JSON with a linter before submission.

Example fix

# before
inputs:
  - id: choice
    type: SELECT
    options:
      - label: Foo   # missing value

# after
inputs:
  - id: choice
    type: SELECT
    options:
      - value: foo
        label: Foo
      # or shorthand
      - foo
Defensive patterns

Strategy: validation

Validate before calling

if (raw instanceof Map<?,?> map && !map.containsKey("value")) {
    throw new IllegalArgumentException("Select option object must define a `value` field");
}

Type guard

function isValueOptionMap(o): o is { value: unknown; label?: unknown } {
  return typeof o === 'object' && o !== null && 'value' in o;
}

Try / catch

try {
    ValueOption.from(raw);
} catch (IllegalArgumentException e) {
    // highlight the offending option in the flow editor
    errors.add("Each SELECT option object needs a 'value' field.");
}

Prevention

When it happens

Trigger: A SELECT input defines an option as {"label":"Foo"} with no value; an option map is {"name":"x"} instead of {"value":"x"}; malformed YAML/JSON in the flow's options list.

Common situations: Typo in the option key ('val' instead of 'value'); copy-paste from another schema; YAML auto-converted a key name.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/4b32c125133d35a3. Report an issue: GitHub.