{"record":{"id":"94797a418a14ef85","repo":"databendlabs/databend","slug":"dataexchange-broadcast-unreachable","errorCode":null,"errorMessage":"DataExchange::Broadcast(_) => unreachable!()","messagePattern":"DataExchange::Broadcast\\(_\\) => unreachable!\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/service/src/pipelines/processors/transforms/aggregator/aggregate_exchange_injector.rs","lineNumber":65,"sourceCode":"        shuffle_mode: AggregateShuffleMode,\n    ) -> Arc<dyn ExchangeInjector> {\n        Arc::new(AggregateInjector {\n            ctx,\n            aggregator_params: params,\n            shuffle_mode,\n        })\n    }\n}\n\nimpl ExchangeInjector for AggregateInjector {\n    fn flight_scatter(\n        &self,\n        _: &Arc<QueryContext>,\n        exchange: &DataExchange,\n    ) -> Result<Arc<Box<dyn FlightScatter>>> {\n        match exchange {\n            DataExchange::Merge(_) => unreachable!(),\n            DataExchange::Broadcast(_) => unreachable!(),\n            DataExchange::GlobalShuffleExchange(_) => unreachable!(),\n            DataExchange::NodeToNodeExchange(exchange) => match self.shuffle_mode {\n                AggregateShuffleMode::Row => Ok(Arc::new(Box::new(AggregateRowScatter {\n                    buckets: exchange.destination_ids.len(),\n                    aggregate_params: self.aggregator_params.clone(),\n                }))),\n                AggregateShuffleMode::Bucket(_) => Ok(Arc::new(Box::new(AggregateBucketScatter {\n                    buckets: exchange.destination_ids.len(),\n                }))),\n            },\n        }\n    }\n\n    fn exchange_sorting(&self) -> Option<Arc<dyn ExchangeSorting>> {\n        None\n    }\n\n    fn apply_merge_serializer(","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/pipelines/processors/transforms/aggregator/aggregate_exchange_injector.rs#L47-L83","documentation":"`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.","triggerScenarios":"`flight_scatter` is called with a `DataExchange::Broadcast` plan fragment, meaning aggregate injection was attempted on a broadcast-distribution plan.","commonSituations":"Optimizer bug in exchange planning for distributed aggregation; queries whose GROUP BY pattern unexpectedly planned a broadcast exchange where a shuffle was expected.","solutions":["Use EXPLAIN to inspect the exchange chosen for the aggregation in the failing query","Report/check for planner regressions where aggregate injection was applied to broadcast exchanges","Convert the panic into a planner error to fail the query gracefully","Upgrade Databend to get planner fixes for exchange-injection classification"],"exampleFix":"// before\nDataExchange::Broadcast(_) => unreachable!(),\n// after\nDataExchange::Broadcast(_) => Err(ErrorCode::Unimplemented(\"aggregate shuffle does not support Broadcast exchange\")),","handlingStrategy":"validation","validationCode":"if matches!(exchange, DataExchange::Broadcast(_)) { return Err(ErrorCode::Unimplemented(\"aggregate injection unsupported for Broadcast\")); }","typeGuard":"fn is_shuffle_exchange(e: &DataExchange) -> bool { matches!(e, DataExchange::NodeToNodeExchange(_)) }","tryCatchPattern":null,"preventionTips":["Verify the optimizer never pairs broadcast exchanges with aggregate injection","Add plan-level assertions in tests for aggregation over broadcast inputs","Return typed planner errors for unsupported exchange kinds"],"tags":["rust","panic","query-planning","distributed"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}