databendlabs/databend · error

DataExchange::Broadcast(_) => unreachable!()

Error message

DataExchange::Broadcast(_) => unreachable!()

What it means

`AggregateExchangeInjector::flight_scatter` panics when it receives a `DataExchange::Broadcast` exchange. Broadcast exchanges fan a block to all nodes and are incompatible with aggregate shuffle injection, which only applies to node-to-node shuffles of the aggregated partial state.

Solutions

  1. Use EXPLAIN to inspect the exchange chosen for the aggregation in the failing query
  2. Report/check for planner regressions where aggregate injection was applied to broadcast exchanges
  3. Convert the panic into a planner error to fail the query gracefully
  4. Upgrade Databend to get planner fixes for exchange-injection classification

Example fix

// before
DataExchange::Broadcast(_) => unreachable!(),
// after
DataExchange::Broadcast(_) => Err(ErrorCode::Unimplemented("aggregate shuffle does not support Broadcast exchange")),
Defensive patterns

Strategy: validation

Validate before calling

if matches!(exchange, DataExchange::Broadcast(_)) { return Err(ErrorCode::Unimplemented("aggregate injection unsupported for Broadcast")); }

Type guard

fn is_shuffle_exchange(e: &DataExchange) -> bool { matches!(e, DataExchange::NodeToNodeExchange(_)) }

Prevention

When it happens

Trigger: `flight_scatter` is called with a `DataExchange::Broadcast` plan fragment, meaning aggregate injection was attempted on a broadcast-distribution plan.

Common situations: Optimizer bug in exchange planning for distributed aggregation; queries whose GROUP BY pattern unexpectedly planned a broadcast exchange where a shuffle was expected.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/94797a418a14ef85. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/pipelines/processors/transforms/aggregator/aggregate_exchange_injector.rs:65

        shuffle_mode: AggregateShuffleMode,
    ) -> Arc<dyn ExchangeInjector> {
        Arc::new(AggregateInjector {
            ctx,
            aggregator_params: params,
            shuffle_mode,
        })
    }
}

impl ExchangeInjector for AggregateInjector {
    fn flight_scatter(
        &self,
        _: &Arc<QueryContext>,
        exchange: &DataExchange,
    ) -> Result<Arc<Box<dyn FlightScatter>>> {
        match exchange {
            DataExchange::Merge(_) => unreachable!(),
            DataExchange::Broadcast(_) => unreachable!(),
            DataExchange::GlobalShuffleExchange(_) => unreachable!(),
            DataExchange::NodeToNodeExchange(exchange) => match self.shuffle_mode {
                AggregateShuffleMode::Row => Ok(Arc::new(Box::new(AggregateRowScatter {
                    buckets: exchange.destination_ids.len(),
                    aggregate_params: self.aggregator_params.clone(),
                }))),
                AggregateShuffleMode::Bucket(_) => Ok(Arc::new(Box::new(AggregateBucketScatter {
                    buckets: exchange.destination_ids.len(),
                }))),
            },
        }
    }

    fn exchange_sorting(&self) -> Option<Arc<dyn ExchangeSorting>> {
        None
    }

    fn apply_merge_serializer(

View on GitHub (pinned to 288d84d76e)