quickwit-oss/tantivy · error

Internal Error: Called get_val of empty column.

Error message

Internal Error: Called get_val of empty column.

What it means

EmptyColumnValues is a sentinel implementation of ColumnValues for a column with zero rows. Its get_val always panics because there is no value at any index. It is intentional: random access into an empty column is undefined and callers are expected to use min_value/max_value or empty iteration instead.

Source

Thrown at columnar/src/column_values/mod.rs:184

    /// ∃i < self.num_vals(), self.get_val(i) == self.max_value()
    fn max_value(&self) -> T;

    /// The number of values in the column.
    fn num_vals(&self) -> u32;

    /// Returns a iterator over the data
    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a> {
        Box::new((0..self.num_vals()).map(|idx| self.get_val(idx)))
    }
}
downcast_rs::impl_downcast!(sync ColumnValues<T> where T: PartialOrd);

/// Empty column of values.
pub struct EmptyColumnValues;

impl<T: PartialOrd + Default> ColumnValues<T> for EmptyColumnValues {
    fn get_val(&self, _idx: u32) -> T {
        panic!("Internal Error: Called get_val of empty column.")
    }

    fn min_value(&self) -> T {
        T::default()
    }

    fn max_value(&self) -> T {
        T::default()
    }

    fn num_vals(&self) -> u32 {
        0
    }
}

impl<T: Copy + PartialOrd + Debug + 'static> ColumnValues<T> for Arc<dyn ColumnValues<T>> {
    #[inline(always)]
    fn get_val(&self, idx: u32) -> T {

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Check column.num_vals() (or doc count) before calling get_val/get_vals and skip empty columns.
  2. Use get_vals_opt / iter which tolerate empty columns, or rely on min_value/max_value defaults for statistics.
  3. Guard range queries: if the requested range overlaps no rows, return an empty result without touching values.

Example fix

// before
let val = column.values().get_val(doc_id);
// after
if column.num_vals() == 0 {
    return Vec::new(); // empty column has no values
}
let val = column.values().get_val(doc_id);
Defensive patterns

Strategy: validation

Validate before calling

if column.num_vals() == 0 {
    return Ok(Vec::new());
}
let val = column.values().get_val(idx);

Type guard

fn is_empty_column<T>(col: &dyn ColumnValues<T>) -> bool {
    col.num_vals() == 0
}

Try / catch

// panics are not catchable in Rust; guard instead
assert!(column.num_vals() > 0, "cannot read value from empty column");

Prevention

When it happens

Trigger: Calling get_val(idx) (directly or via get_vals, get_vals_opt, get_range, get_row_ids_for_value_range, or iter) on a column backed by EmptyColumnValues — i.e. any column with 0 rows — with any index.

Common situations: Querying/collecting over an empty segment or an empty table shard; a filter eliminated all docs before aggregation reads values; opening a column family that exists but has no rows; code that iterates columns by doc_id range without checking num_vals() == 0.

Related errors


AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05). Data as JSON: /api/errors/a3fdeac61a3e886e. Report an issue: GitHub.