{"record":{"id":"bcb8b8421b97e87a","repo":"kestra-io/kestra","slug":"found-a-null-value-inside-the-iteration-values","errorCode":null,"errorMessage":"Found a null value inside the iteration values={}","messagePattern":"Found a null value inside the iteration values=(.+?)","errorType":"exception","errorClass":"IllegalVariableEvaluationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/runners/FlowableUtils.java","lineNumber":432,"sourceCode":"     *\n     * @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.\n     * @throws IllegalVariableEvaluationException in case of JSON error, unsupported value type or duplicate values.\n     */\n    public static Either<List<String>, List<Pair<String, String>>> resolveValues(RunContext runContext, Object values) throws IllegalVariableEvaluationException {\n        switch (values) {\n            case String stringValue -> {\n                String renderValue = runContext.render(stringValue);\n                try {\n                    JsonNode valuesNode = MAPPER.readTree(renderValue);\n                    if (valuesNode.isArray()) {\n                        List<String> resolvedValues = MAPPER.convertValue(valuesNode, TYPE_REFERENCE)\n                            .stream()\n                            .map(throwFunction(obj ->\n                            {\n                                if (obj instanceof String s) {\n                                    return s;\n                                } else if (obj == null) {\n                                    throw new IllegalVariableEvaluationException(\n                                        \"Found a null value inside the iteration values=\" + serializeAsString(values)\n                                    );\n                                } else {\n                                    return serializeAsString(obj);\n                                }\n                            }))\n                            .distinct()\n                            .toList();\n                        return Either.left(resolvedValues);\n                    } else if (valuesNode.isObject()) {\n                        List<Pair<String, String>> resolvedValues = new ArrayList<>();\n                        Map<String, Object> mapValues = MAPPER.convertValue(valuesNode, JacksonMapper.MAP_TYPE_REFERENCE);\n                        for (var entry : mapValues.entrySet()) {\n                            resolvedValues.add(Pair.of(entry.getKey(), valueAsString(runContext, values, entry.getValue())));\n                        }\n                        return Either.right(resolvedValues);\n                    } else {\n                        throw new IllegalVariableEvaluationException(\"Unknown value type: \" + valuesNode.getNodeType());","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/runners/FlowableUtils.java#L414-L450","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Filter nulls out of the rendered array before iteration: `{{ mylist | filter(v => v != null) }}`.","Fix the upstream source so no array element is null.","If null is meaningful, replace it with a sentinel string (e.g. \"null\" or \"\") in the source data."],"exampleFix":"# before\ntasks:\n  - id: loop\n    type: io.kestra.plugin.core.flow.ForEach\n    values: \"{{ outputs.query.rows }}\" # rows may contain null entries\n\n# after — drop nulls\n    values: \"{{ outputs.query.rows | filter(r => r != null) }}\"","handlingStrategy":"validation","validationCode":"// Strip nulls from a JSON-array string before resolveValues\nString rendered = runContext.render(valuesExpr);\nJsonNode node = MAPPER.readTree(rendered);\nif (node.isArray()) {\n    List<Object> clean = new ArrayList<>();\n    node.forEach(n -> { if (!n.isNull()) clean.add(MAPPER.treeToValue(n, Object.class)); });\n    values = MAPPER.writeValueAsString(clean);\n}","typeGuard":null,"tryCatchPattern":"try {\n    Either.leftOrRight(FlowableUtils.resolveValues(runContext, values));\n} catch (IllegalVariableEvaluationException e) {\n    if (e.getMessage().startsWith(\"Found a null value\")) {\n        runContext.logger().error(\"Iteration values contained null; filtering them out.\");\n        // re-run after filter\n    } else throw e;\n}","preventionTips":["Sanitize iteration sources with a Pebble filter: `{{ list | filter(v => v != null) }}`.","Prefer non-nullable columns in upstream SQL/query outputs.","Add a data-quality task before the loop to reject null rows."],"tags":["iteration","foreach","null","json","flowable"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}