risingwavelabs/risingwave · error · BatchError

MergeSortExchangeExecutor should not have child!

Error message

MergeSortExchangeExecutor should not have child!

What it means

`MergeSortExchangeExecutorBuilder::new_boxed_executor` requires that a MergeSortExchange plan node has no child executors; the merge-sort exchange pulls its inputs from remote exchange sources rather than a local child. A non-empty `inputs` vector means the executor tree is structurally invalid, so plan construction fails with this message (which says "should not have child").

Source

Thrown at src/batch/executors/src/executor/merge_sort_exchange.rs:131

            self.chunk_size,
            self.mem_ctx,
        ));

        #[for_await]
        for chunk in merge_sort_executor.execute() {
            yield chunk?;
        }
    }
}

pub struct MergeSortExchangeExecutorBuilder {}

impl BoxedExecutorBuilder for MergeSortExchangeExecutorBuilder {
    async fn new_boxed_executor(
        source: &ExecutorBuilder<'_>,
        inputs: Vec<BoxedExecutor>,
    ) -> Result<BoxedExecutor> {
        ensure!(
            inputs.is_empty(),
            "MergeSortExchangeExecutor should not have child!"
        );
        let sort_merge_node = try_match_expand!(
            source.plan_node().get_node_body().unwrap(),
            NodeBody::MergeSortExchange
        )?;

        let column_orders = sort_merge_node
            .column_orders
            .iter()
            .map(ColumnOrder::from_protobuf)
            .collect();
        let column_orders = Arc::new(column_orders);

        let exchange_node = sort_merge_node.get_exchange()?;
        let proto_sources: Vec<PbExchangeSource> = exchange_node.get_sources().clone();
        let source_creators =

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Verify the distributed plan: MergeSortExchange must have no local child; its receiver should be a separate MergeSortExchangeReceiver node.
  2. Upgrade meta and compute nodes to matching versions to rule out plan-format skew.
  3. If reproducible from a normal query, capture the fragment and file a RisingWave issue with the EXPLAIN output.
Defensive patterns

Strategy: validation

Validate before calling

// validate plan shape before dispatching the fragment
fn assert_exchange_shape(node: &PlanNode) -> Result<()> {
    if matches!(node.node_body, Some(NodeBody::MergeSortExchange(_))) {
        ensure!(node.children.is_empty(), "MergeSortExchange must not have a local child");
    }
    Ok(())
}

Prevention

When it happens

Trigger: Building a batch executor tree where a `MergeSortExchange` NodeBody has a child attached in the plan fragment — i.e. malformed plan distribution where the node should sit above a MergeSortExchangeReceiver but was given local input.

Common situations: Version skew or bugs in meta's plan distribution placing the node incorrectly; hand-crafted plan fragments in tests; corrupted exchange wiring after scheduler changes.

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 risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/80f916010ca7159e. Report an issue: GitHub.