quickwit-oss/quickwit · error
`{SORTED_SERIES_COLUMN}` must be Binary-typed
Error message
`{SORTED_SERIES_COLUMN}` must be Binary-typed What it means
split_region_at_sorted_series expects the SORTED_SERIES_COLUMN to be a BinaryArray when present in the batch schema. If the column exists but its physical array type is not BinaryArray (e.g. LargeBinaryArray or Utf8), the downcast fails with this error. It is an internal contract check between the sorted_series writer and the streaming merge reader.
Source
Thrown at quickwit/quickwit-parquet-engine/src/merge/streaming/region_grouping.rs:710
if merge_order.is_empty() {
return Ok(Vec::new());
}
if outputs_remaining <= 1 {
return Ok(vec![region.clone()]);
}
// Per-input sorted_series array. compute_merge_order already
// requires this column on every input, so a missing-column case
// here is a bug rather than a configuration error.
let mut ss_arrays: Vec<Option<&BinaryArray>> = Vec::with_capacity(aligned_sort_batches.len());
for batch in aligned_sort_batches {
match batch.schema().index_of(SORTED_SERIES_COLUMN) {
Ok(idx) => {
let arr = batch
.column(idx)
.as_any()
.downcast_ref::<BinaryArray>()
.ok_or_else(|| anyhow!("`{SORTED_SERIES_COLUMN}` must be Binary-typed"))?;
ss_arrays.push(Some(arr));
}
Err(_) => ss_arrays.push(None),
}
}
let ss_at = |run_idx: usize| -> Option<&[u8]> {
let run = &merge_order[run_idx];
ss_arrays[run.input_index].map(|a| a.value(run.start_row))
};
// Walk runs, splitting before a run whose preceding sorted_series
// transition crosses the current target. We can only split at run
// boundaries (a run has constant sorted_series internally), so
// breaking inside a run is impossible — a giant single-series run
// simply lands in one output regardless of size.
let mut splits: Vec<std::ops::Range<usize>> = Vec::new();
let mut current_start: usize = 0;View on GitHub (pinned to a39730c5cd)
Solutions
- Ensure append_sorted_series_column is the single producer of this column (it emits DataType::Binary) and that no intermediate step recasts it.
- Add an arrow::compute::cast to Binary before split_region_at_sorted_series if a recast is unavoidable.
- Check for a duplicate ad-hoc producer of SORTED_SERIES_COLUMN with the wrong type.
Example fix
// before
let arr = batch.column(idx).as_any().downcast_ref::<BinaryArray>()...;
// after
let col = arrow::compute::cast(batch.column(idx), &DataType::Binary)?;
let arr = col.as_any().downcast_ref::<BinaryArray>().ok_or_else(|| anyhow!("cast failed"))?; Defensive patterns
Strategy: type-guard
Validate before calling
if let Ok(idx) = batch.schema().index_of(SORTED_SERIES_COLUMN) {
debug_assert_eq!(batch.schema().field(idx).data_type(), &DataType::Binary);
}
Type guard
fn is_binary_sorted_series(batch: &RecordBatch) -> bool {
batch.schema().index_of(SORTED_SERIES_COLUMN)
.map(|i| batch.column(i).data_type() == &DataType::Binary
&& batch.column(i).as_any().is::<BinaryArray>())
.unwrap_or(true)
}
Try / catch
match result {
Err(e) if e.to_string().contains("must be Binary-typed") => {
// recast and retry
let cast = arrow::compute::cast(&col, &DataType::Binary)?;
// retry split with cast batch
}
other => other,
}
Prevention
- Produce SORTED_SERIES_COLUMN only via append_sorted_series_column, which emits DataType::Binary.
- Avoid arrow::compute::cast or projections that change the column's physical type mid-pipeline.
- Assert the column type in any test fixture that hand-builds batches containing sorted_series.
When it happens
Trigger: streaming_merge_sorted_parquet_files consuming record batches that contain the sorted_series column produced/typed as something other than DataType::Binary — e.g. a schema change to LargeBinary upstream, or the column built as Utf8 instead of Binary.
Common situations: A producer that changed the column type (Utf8/LargeBinary) without updating the merge path; hand-built test batches with the wrong array type; a parquet round-trip that altered the physical type.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- sort schema '{}' does not contain a timestamp column
- input {} is missing column '{}'
- expected LargeStringArray for service col page
- timestamp_secs must be UInt64 or Int64 for MC-3 check
- input file {} is missing the '{}' column
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/92a471edb0a994d5.
Report an issue: GitHub.