quickwit-oss/tantivy · error
unexpected aggregation, expected composite aggregation
Error message
unexpected aggregation, expected composite aggregation
What it means
A panic in `into_final_bucket_result`: `IntermediateBucketResult::Composite` is finalized with `req.agg.as_composite().expect("unexpected aggregation, expected composite aggregation")`, which fires when the request's aggregation is not a composite aggregation. This is the same family of request/intermediate-result type mismatches: the intermediate bucket result claims composite but the request definition does not.
Source
Thrown at src/aggregation/intermediate_agg_result.rs:714
limits,
),
IntermediateBucketResult::Filter {
doc_count,
sub_aggregations,
} => {
// Convert sub-aggregation results to final format
let final_sub_aggregations = sub_aggregations
.into_final_result(req.sub_aggregation().clone(), limits.clone())?;
Ok(BucketResult::Filter(FilterBucketResult {
doc_count,
sub_aggregations: final_sub_aggregations,
}))
}
IntermediateBucketResult::Composite { buckets } => {
let composite_req = req
.agg
.as_composite()
.expect("unexpected aggregation, expected composite aggregation");
buckets.into_final_result(composite_req, req.sub_aggregation(), limits)
}
IntermediateBucketResult::MultiTerms { buckets } => {
let multi_terms_req = req
.agg
.as_multi_terms()
.expect("unexpected aggregation, expected multi_terms aggregation");
buckets.into_final_result(multi_terms_req, req.sub_aggregation(), limits)
}
}
}
pub(crate) fn prune_intermediate_results(
&mut self,
req: &Aggregation,
mode: PruneMode,
) -> crate::Result<()> {
match self {View on GitHub (pinned to b5d8deb80c)
Solutions
- Use the original request object for finalization; never reuse intermediates across requests.
- Keep all cluster nodes on the same engine version.
- Verify the aggregation tree sent to shards matches the one used by the coordinator for finalization.
- If you maintain the code, propagate an internal error via ok_or instead of expecting.
Example fix
// before
req.agg.as_composite().expect("unexpected aggregation, expected composite aggregation")
// after
req.agg.as_composite()
.ok_or_else(|| crate::AggregationError::Internal("expected composite agg".to_string()))? Defensive patterns
Strategy: validation
Validate before calling
fn is_composite_agg(req: &Aggregation) -> bool {
matches!(req, Aggregation::Composite(_))
}
// check before finalizing composite intermediates Type guard
fn as_composite(req: &Aggregation) -> Option<&CompositeAgg> {
if let Aggregation::Composite(c) = req { Some(c) } else { None }
} Try / catch
let res = std::panic::catch_unwind(|| buckets.into_final_result(composite_req, sub_agg, limits));
if res.is_err() {
return internal_error("expected composite aggregation during finalization");
} Prevention
- Finalize composite aggregations with the same request object that shards executed.
- Do not rebuild the aggregation tree (rename/reorder aggs) mid-query.
- Verify intermediate-result format compatibility across engine versions.
When it happens
Trigger: Finalizing composite aggregation intermediate results when `req.agg` resolves to a non-composite aggregation — mismatched aggregation ids during distributed merging, version-skewed nodes, or intermediate results paired with the wrong request.
Common situations: Rolling upgrades where shard responses follow a different intermediate format; cache hits returning intermediates from another query; custom tooling rebuilding the aggregation request tree.
Related errors
- unexpected metric type
- unexpected aggregation, expected histogram aggregation
- unexpected aggregation, expected range aggregation
- unexpected aggregation, expected term aggregation
- TermMissingAgg collector, but no missing found in agg req
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/891047e3be23e5dc.
Report an issue: GitHub.