quickwit-oss/tantivy · critical

No multivalued index is allowed when stacking column index

Error message

No multivalued index is allowed when stacking column index

What it means

When stacking (merging) columnar column indexes, the code can only handle Optional (single-valued) and Empty indexes. If a Multivalued column index is encountered it cannot be expressed as a flat row iterator, so the library panics. This is an internal invariant violation: a multivalued column reached a merge path that only supports single-valued columns.

Source

Thrown at columnar/src/column_index/merge/stacked.rs:185

}

impl<'a> Iterable<RowId> for StackedOptionalIndex<'a> {
    fn boxed_iter(&self) -> Box<dyn Iterator<Item = RowId> + 'a> {
        Box::new(
            self.columns
                .iter()
                .enumerate()
                .flat_map(|(columnar_id, column_index_opt)| {
                    let columnar_row_range = self.stack_merge_order.columnar_range(columnar_id);
                    let rows_it: Box<dyn Iterator<Item = RowId>> = match column_index_opt {
                        ColumnIndex::Full => Box::new(columnar_row_range),
                        ColumnIndex::Optional(optional_index) => Box::new(
                            optional_index
                                .iter_non_null_docs()
                                .map(move |row_id: RowId| columnar_row_range.start + row_id),
                        ),
                        ColumnIndex::Multivalued(_) => {
                            panic!("No multivalued index is allowed when stacking column index");
                        }
                        ColumnIndex::Empty { .. } => Box::new(std::iter::empty()),
                    };
                    rows_it
                }),
        )
    }
}

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Do not stack/merge multivalued columns with this API; check column cardinality first and skip or handle multivalued columns separately.
  2. Use the multivalued-aware merge path (e.g. merging full columns with Column::merge, which handles multivalued indexes) instead of the stacked index merge.
  3. If this is unexpected, verify the column's index type with a debug assert and report a bug to tantivy-columnar maintainers with the segment data.

Example fix

// before
for column in columns {
    stacked.push(column.stack(other)); // panics on multivalued
}
// after
for column in columns {
    if column.get_cardinality() != Cardinality::Multivalued {
        stacked.push(column.stack(other));
    } else {
        // handle multivalued columns via the full-column merge API
        merged_multivalued.push(Column::merge(column.clone(), other.clone()));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if column.get_cardinality() == Cardinality::Multivalued {
    return Err("cannot stack multivalued column".into());
}
stacked.push(column.stack(other));

Type guard

fn is_stackable(card: Cardinality) -> bool {
    matches!(card, Cardinality::Optional | Cardinality::Full)
}

Prevention

When it happens

Trigger: Calling columnar stack/merge APIs (e.g. stacking columns via Column::merge / stacked column building) on a column whose ColumnIndex is ColumnIndex::Multivalued; i.e. merging a multivalued (array) column through the stacked column-index merge path in columnar/src/column_index/merge/stacked.rs.

Common situations: Merging or stacking segments/tables that contain array (multivalued) fields; passing a column built from repeated values into an API documented for single-valued columns; custom tooling that iterates all columns of a table and stacks them without filtering column type (multivalued => Cardinality::Multivalued).

Related errors


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