influxdata/influxdb · error · Error

The Record batch is empty

Error message

The Record batch is empty

What it means

Returned by compute_timenanosecond_min_max_for_one_record_batch when the record batch has no columns (EmptyBatchSnafu). The function scans the `time` column to compute min/max, which is impossible on an empty-schema batch, so it fails fast with this error.

Solutions

  1. Check batch.num_columns() > 0 before calling the helper
  2. Ensure the query projection always includes the time column
  3. Skip empty batches in the caller loop and aggregate the rest

Example fix

// before
let (min, max) = compute_timenanosecond_min_max_for_one_record_batch(&batch)?;
// after
if batch.num_columns() == 0 {
    continue; // or return a default range
}
let (min, max) = compute_timenanosecond_min_max_for_one_record_batch(&batch)?;
Defensive patterns

Strategy: validation

Validate before calling

if batch.num_columns() == 0 { return Ok(default_range); }

Type guard

fn has_columns(b: &RecordBatch) -> bool { b.num_columns() > 0 }

Try / catch

match compute_timenanosecond_min_max_for_one_record_batch(&batch) {
    Err(e) if matches!(e.find_root(), EmptyBatchError) => return default,
    other => other?,
}

Prevention

When it happens

Trigger: Calling compute_timenanosecond_min_max (or the per-batch helper) with a RecordBatch created with zero columns — e.g. an empty projection or a batch built from an empty schema.

Common situations: Query plans that select no columns alongside time bounds; record batches constructed manually in tests with an empty schema; upstream chunks yielding degenerate empty batches.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/4341dfb36cface8d. Report an issue: GitHub.

Appendix: source

Thrown at core/iox_query/src/util.rs:104

    let mut min_time = i64::MAX;
    let mut max_time = i64::MIN;
    for batch in batches {
        let (mi, ma) = compute_timenanosecond_min_max_for_one_record_batch(batch)?;
        min_time = min(min_time, mi);
        max_time = max(max_time, ma);
    }
    Ok(TimestampMinMax {
        min: min_time,
        max: max_time,
    })
}

/// Return min and max for column `time` in the given record batch by performing
/// an `O(n)` scan of `batch`.
pub fn compute_timenanosecond_min_max_for_one_record_batch(
    batch: &RecordBatch,
) -> Result<(i64, i64)> {
    ensure!(batch.num_columns() > 0, EmptyBatchSnafu);

    let index = batch
        .schema()
        .index_of(TIME_COLUMN_NAME)
        .context(TimeColumnSnafu {})?;

    let time_col = batch
        .column(index)
        .as_any()
        .downcast_ref::<TimestampNanosecondArray>()
        .context(TimeCastingSnafu {})?;

    let (min, max) = match time_col.iter().minmax() {
        itertools::MinMaxResult::NoElements => return Err(Error::TimeValue),
        itertools::MinMaxResult::OneElement(val) => {
            let val = val.context(TimeNullSnafu)?;
            (val, val)
        }

View on GitHub (pinned to 06200ef96b)