kestra-io/kestra · error · IllegalArgumentException

Unable to deserialize value as it's neither an object neithe

Error message

Unable to deserialize value as it's neither an object neither an array

What it means

The `ListOrMapOfLabelDeserializer` only handles three JSON token types: `VALUE_NULL`, `START_ARRAY`, and `START_OBJECT`. If the labels field is any other token type (e.g., a bare string, number, or boolean scalar), it falls through all branches and throws `IllegalArgumentException`. This means the labels field was provided as a raw scalar value rather than a structured array or object.

Source

Thrown at core/src/main/java/io/kestra/core/serializers/ListOrMapOfLabelDeserializer.java:46

            List<Map<String, String>> ret = ctxt.readValue(p, List.class);
            return ret.stream().map(map ->
            {
                Object value = map.get("value");
                if (isAllowedType(value)) {
                    return new Label(map.get("key"), String.valueOf(value));
                } else {
                    throw new IllegalArgumentException("Unsupported type for key: " + map.get("key") + ", value: " + value);
                }
            }).toList();
        } else if (p.hasToken(JsonToken.START_OBJECT)) {
            // deserialize as map
            Map<String, Object> ret = ctxt.readValue(p, Map.class);
            return ret == null ? null
                : ret.entrySet().stream()
                    .map(this::validateAndCreateLabel)
                    .toList();
        }
        throw new IllegalArgumentException("Unable to deserialize value as it's neither an object neither an array");
    }

    private Label validateAndCreateLabel(Map.Entry<String, Object> entry) {
        Object value = entry.getValue();
        if (isAllowedType(value)) {
            return new Label(entry.getKey(), String.valueOf(value));
        } else {
            throw new IllegalArgumentException("Unsupported type for key: " + entry.getKey() + ", value: " + value);
        }
    }

    private static boolean isAllowedType(Object value) {
        return value instanceof String ||
            value instanceof Integer ||
            value instanceof Long ||
            value instanceof Float ||
            value instanceof Double ||
            value instanceof Boolean;

View on GitHub (pinned to 823fada927)

Solutions

  1. Provide labels as either a JSON array of `{key, value}` objects or a JSON map of `{key: value}` pairs.
  2. If no labels are needed, omit the field entirely or set it to null, not an empty string.

Example fix

# before
labels: "my-label"
# after
labels:
  - key: my-label
    value: "true"
Defensive patterns

Strategy: validation

Validate before calling

// Validate that labels is an array or object before deserialization
import com.fasterxml.jackson.databind.JsonNode;

public static void validateLabelsShape(JsonNode labelsNode) {
    if (labelsNode == null || labelsNode.isNull()) return;
    if (!labelsNode.isArray() && !labelsNode.isObject()) {
        throw new IllegalArgumentException(
            "labels must be a JSON array or object, got: " + labelsNode.getNodeType());
    }
}

Type guard

function isLabelContainer(v: unknown): boolean {
    return Array.isArray(v) || (typeof v === 'object' && v !== null);
}

Prevention

When it happens

Trigger: Submitting `"labels": "some_string"` or `"labels": 42` in a flow/execution JSON payload. The labels field must be a JSON array or object, not a scalar.

Common situations: An API consumer mistakenly passes a single string instead of a list or map of labels. A malformed JSON payload where the labels field is a bare value due to a serialization bug.

Related errors


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