quickwit-oss/tantivy · error

All columns re required to be numerical

Error message

All columns re required to be numerical

What it means

merged_numerical_columns_type computes the numerical type resulting from merging several dynamic columns; min_max_if_numerical returns None for non-numerical columns and the code .expect()s, panicking with "All columns re required to be numerical". The contract is that callers (e.g. column_type_after_merge) only pass columns already known to be numerical (i64/u64/f64). If any column is Str/Bool/Bytes/etc., the precondition is violated and the process panics.

Source

Thrown at columnar/src/columnar/merge/mod.rs:343

        self.required_column_type = Some(required_type);
        Ok(())
    }
}

/// Returns the type of the merged numerical column.
///
/// This function picks the first numerical type out of i64, u64, f64 (order matters
/// here), that is compatible with all the `columns`.
///
/// # Panics
/// Panics if one of the column is not numerical.
fn merged_numerical_columns_type<'a>(
    columns: impl Iterator<Item = &'a DynamicColumn>,
) -> NumericalType {
    let mut compatible_numerical_types = CompatibleNumericalTypes::default();
    for column in columns {
        let (min_value, max_value) =
            min_max_if_numerical(column).expect("All columns re required to be numerical");
        compatible_numerical_types.accept_value(min_value);
        compatible_numerical_types.accept_value(max_value);
    }
    compatible_numerical_types.to_numerical_type()
}

fn is_empty_after_merge(
    merge_row_order: &MergeRowOrder,
    column: &DynamicColumn,
    columnar_ord: usize,
) -> bool {
    if column.num_values() == 0u32 {
        // It was empty before the merge.
        return true;
    }
    match merge_row_order {
        MergeRowOrder::Stack(_) => {
            // If we are stacking the columnar, no rows are being deleted.

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Fix the caller to filter/min_max_if_numerical-check first, merging only columns where min_max_if_numerical returns Some.
  2. Ensure all writers to a given field emit the same column type; fix ingestion so a field never mixes Str and numeric columns.
  3. If a mixed merge is legitimately possible, replace the expect with a fallback (e.g. skip non-numerical or return an error) in merged_numerical_columns_type.
  4. Re-build/re-write the affected columnar field with a consistent type before merging.

Example fix

// before
let numerical_type = merged_numerical_columns_type(all_columns.iter());
// after
let numerical_cols = all_columns.iter().filter(|c| min_max_if_numerical(c).is_some());
let numerical_type = merged_numerical_columns_type(numerical_cols);
Defensive patterns

Strategy: type-guard

Validate before calling

// Filter to numerical columns before merging types
let numerical_columns: Vec<&DynamicColumn> = columns
    .iter()
    .filter(|c| matches!(c.type_(), ColumnType::I64 | ColumnType::U64 | ColumnType::F64))
    .collect();
if numerical_columns.is_empty() { return Err(/* no numerical columns */); }

Type guard

fn is_numerical(col: &DynamicColumn) -> bool {
    matches!(col.type_(), ColumnType::I64 | ColumnType::U64 | ColumnType::F64)
}

Prevention

When it happens

Trigger: Calling column_type_after_merge / merged_numerical_columns_type over an iterator containing at least one non-numerical DynamicColumn, e.g. merging columnar field data where some columns for a logical field are Str while others are numeric.

Common situations: Merging segments or columnar fields whose type drifted (schema-less columnar ingestion writing mixed types under one field name); a bug where the caller forgot to filter to numerical columns before this function.

Related errors


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