quickwit-oss/tantivy · error

unexpected aggregation, expected histogram aggregation

Error message

unexpected aggregation, expected histogram aggregation

What it means

A panic in `into_final_bucket_result` while finalizing a range aggregation's buckets: the code expects `req.agg.as_range()` to succeed, with a (confusingly worded) message saying "expected histogram aggregation". The panic means the intermediate bucket result is a range-type result but the request's aggregation definition is not a range aggregation, so the request and the intermediate result disagree on aggregation type.

Source

Thrown at src/aggregation/intermediate_agg_result.rs:633

}

impl IntermediateBucketResult {
    pub(crate) fn into_final_bucket_result(
        self,
        req: &Aggregation,
        limits: &mut AggregationLimitsGuard,
    ) -> crate::Result<BucketResult> {
        match self {
            IntermediateBucketResult::Range(range_res) => {
                let mut buckets: Vec<RangeBucketEntry> = range_res
                    .buckets
                    .into_values()
                    .map(|bucket| {
                        bucket.into_final_bucket_entry(
                            req.sub_aggregation(),
                            req.agg
                                .as_range()
                                .expect("unexpected aggregation, expected histogram aggregation"),
                            range_res.column_type,
                            limits,
                        )
                    })
                    .collect::<crate::Result<Vec<_>>>()?;

                buckets.sort_by(|left, right| {
                    left.from
                        .unwrap_or(f64::MIN)
                        .total_cmp(&right.from.unwrap_or(f64::MIN))
                });

                let is_keyed = req
                    .agg
                    .as_range()
                    .expect("unexpected aggregation, expected range aggregation")
                    .keyed;
                let buckets = if is_keyed {

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Use the original, unchanged request object when calling into_final_bucket_result.
  2. Ensure all cluster nodes use the same engine version so agg ids resolve identically.
  3. Avoid reordering/renaming aggregations between the search request and the finalization pass.
  4. If you maintain the code, replace expect with ok_or to return a typed internal error.

Example fix

// before
req.agg.as_range().expect("unexpected aggregation, expected histogram aggregation")
// after
req.agg.as_range()
    .ok_or_else(|| crate::AggregationError::Internal("expected range agg".to_string()))?
Defensive patterns

Strategy: validation

Validate before calling

fn is_range_agg(req: &Aggregation) -> bool {
    matches!(req, Aggregation::Range(_))
}
// check before calling into_final_bucket_result

Type guard

fn as_range(req: &Aggregation) -> Option<&RangeAgg> {
    if let Aggregation::Range(r) = req { Some(r) } else { None }
}

Try / catch

let res = std::panic::catch_unwind(|| into_final_bucket_result(intermediate, &req, limits));
if res.is_err() {
    return internal_error("range agg finalization: request/intermediate mismatch");
}

Prevention

When it happens

Trigger: Finalizing an intermediate range bucket result where the request's agg (looked up by aggregation id/path) resolves to a non-range aggregation, e.g. due to mismatched aggregation ids in a distributed merge or a rebuilt request tree.

Common situations: Coordinator merging shard results whose aggregation trees differ (version skew); caching intermediate results under wrong keys; programmatically mutating the aggregation request after intermediate results were produced.

Related errors


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