kestra-io/kestra · error · IllegalVariableEvaluationException

Found a null value in the ION file

Error message

Found a null value in the ION file

What it means

Thrown by `ionValueToString` while reading rows from an ION file backing a Loop task's URI-based `values` (see `readLoopValuesFromUri` / `readAndCountLoopValuesFromUri`). Each parsed record is converted to a string; if a record is `null` (an explicit null row in the ION stream), this fires. The ION file is fetched via `URIFetcher` and read with `FileSerde`.

Source

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

        try (var is = new BufferedInputStream(URIFetcher.of(uri).fetch(runContext), FileSerde.BUFFER_SIZE)) {
            List<String> result = new ArrayList<>(count);
            long[] index = { 0 };
            FileSerde.read(is, throwConsumer(record ->
            {
                if (index[0] >= offset && result.size() < count) {
                    result.add(ionValueToString(record));
                }
                index[0]++;
            }));
            return Pair.of(result, offset + result.size());
        }
    }

    private static String ionValueToString(Object parsed) throws IllegalVariableEvaluationException {
        return switch (parsed) {
            case String s -> s;
            case Number n -> n.toString();
            case null -> throw new IllegalVariableEvaluationException("Found a null value in the ION file");
            default -> serializeAsString(parsed);
        };
    }
}

View on GitHub (pinned to 823fada927)

Solutions

  1. Inspect and clean the upstream ION-producing task so it never writes a null record.
  2. Re-run the upstream task that generated the URI to regenerate a clean file.
  3. If the URI is a static file you control, edit it to remove null rows.
  4. Use an intermediate task to filter nulls before passing the URI to the Loop.

Example fix

# before — query may emit null rows into the ION file
tasks:
  - id: data
    type: io.kestra.plugin.jdbc.duckdb.Query
    sql: "SELECT maybe_null_col FROM t"
  - id: loop
    type: io.kestra.plugin.core.flow.Loop
    values: "{{ outputs.data.uri }}"

# after — coalesce nulls in SQL
    sql: "SELECT COALESCE(maybe_null_col, '') AS maybe_null_col FROM t"
Defensive patterns

Strategy: validation

Validate before calling

// Validate the ION file has no null rows before looping
try (var is = new BufferedInputStream(URIFetcher.of(uri).fetch(runContext), FileSerde.BUFFER_SIZE)) {
    FileSerde.read(is, throwConsumer(rec -> {
        if (rec == null) throw new IllegalVariableEvaluationException("ION file contains null row at URI " + uri);
    }));
}

Try / catch

try {
    FlowableUtils.readLoopValuesFromUri(runContext, uri, offset, count);
} catch (IllegalVariableEvaluationException e) {
    if (e.getMessage().equals("Found a null value in the ION file")) {
        runContext.logger().error("ION source at {} has null rows; regenerate or clean it.", uri);
    }
    throw e;
}

Prevention

When it happens

Trigger: A Loop/ForEach task whose `values` resolves to a URI (e.g. a Kestra internal storage URI or a `file://`/`http://` URI) pointing to an ION-encoded file, and that file contains a null record. ION is Kestra's row format for tabular outputs (queries, reads), so a null row can appear when a source has an empty line or a deserialized null object.

Common situations: Iterating over the rows of a SQL query / CSV read where a row serialized as null; a corrupted or partially-written ION file from a crashed upstream task; concatenating ION streams with a trailing null.

Related errors


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