kestra-io/kestra · error · IllegalVariableEvaluationException

Found a null value inside the iteration values={}

Error message

Found a null value inside the iteration values={}

What it means

Thrown by `FlowableUtils.resolveValues` when the `values` of an iteration task (ForEach, Parallel, etc.) is a String that renders to a JSON **array**, and at least one element of that array is JSON `null`. The placeholder is the serialized original `values` object, included so the developer can see the full offending input.

Source

Thrown at core/src/main/java/io/kestra/core/runners/FlowableUtils.java:432

     *
     * @return a list of String with no duplicates if the values were a list, or a list of pairs of String/String if the values were a map.
     * @throws IllegalVariableEvaluationException in case of JSON error, unsupported value type or duplicate values.
     */
    public static Either<List<String>, List<Pair<String, String>>> resolveValues(RunContext runContext, Object values) throws IllegalVariableEvaluationException {
        switch (values) {
            case String stringValue -> {
                String renderValue = runContext.render(stringValue);
                try {
                    JsonNode valuesNode = MAPPER.readTree(renderValue);
                    if (valuesNode.isArray()) {
                        List<String> resolvedValues = MAPPER.convertValue(valuesNode, TYPE_REFERENCE)
                            .stream()
                            .map(throwFunction(obj ->
                            {
                                if (obj instanceof String s) {
                                    return s;
                                } else if (obj == null) {
                                    throw new IllegalVariableEvaluationException(
                                        "Found a null value inside the iteration values=" + serializeAsString(values)
                                    );
                                } else {
                                    return serializeAsString(obj);
                                }
                            }))
                            .distinct()
                            .toList();
                        return Either.left(resolvedValues);
                    } else if (valuesNode.isObject()) {
                        List<Pair<String, String>> resolvedValues = new ArrayList<>();
                        Map<String, Object> mapValues = MAPPER.convertValue(valuesNode, JacksonMapper.MAP_TYPE_REFERENCE);
                        for (var entry : mapValues.entrySet()) {
                            resolvedValues.add(Pair.of(entry.getKey(), valueAsString(runContext, values, entry.getValue())));
                        }
                        return Either.right(resolvedValues);
                    } else {
                        throw new IllegalVariableEvaluationException("Unknown value type: " + valuesNode.getNodeType());

View on GitHub (pinned to 823fada927)

Solutions

  1. Filter nulls out of the rendered array before iteration: `{{ mylist | filter(v => v != null) }}`.
  2. Fix the upstream source so no array element is null.
  3. If null is meaningful, replace it with a sentinel string (e.g. "null" or "") in the source data.

Example fix

# before
tasks:
  - id: loop
    type: io.kestra.plugin.core.flow.ForEach
    values: "{{ outputs.query.rows }}" # rows may contain null entries

# after — drop nulls
    values: "{{ outputs.query.rows | filter(r => r != null) }}"
Defensive patterns

Strategy: validation

Validate before calling

// Strip nulls from a JSON-array string before resolveValues
String rendered = runContext.render(valuesExpr);
JsonNode node = MAPPER.readTree(rendered);
if (node.isArray()) {
    List<Object> clean = new ArrayList<>();
    node.forEach(n -> { if (!n.isNull()) clean.add(MAPPER.treeToValue(n, Object.class)); });
    values = MAPPER.writeValueAsString(clean);
}

Try / catch

try {
    Either.leftOrRight(FlowableUtils.resolveValues(runContext, values));
} catch (IllegalVariableEvaluationException e) {
    if (e.getMessage().startsWith("Found a null value")) {
        runContext.logger().error("Iteration values contained null; filtering them out.");
        // re-run after filter
    } else throw e;
}

Prevention

When it happens

Trigger: A ForEach/Loop task whose `values` is a Pebble expression that renders to a JSON array containing a null entry, e.g. `["a", null, "c"]` or `[{"x":1}, null]`. Common when the expression reads from a nullable output field or a sparse JSON/CSV source.

Common situations: Iteration over a list that has gaps; reading rows from a file/API where a row is null; a `{{ outputs.task.rows | jq(...) }}` that yields nulls for missing columns; mapping over an array of optionals.

Related errors


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