risingwavelabs/risingwave · error

Unexpected node body for stream cdc scan

Error message

Unexpected node body for stream cdc scan

What it means

validate_cdc_table inspects the generated stream fragments of a CDC table to confirm the scan fragment contains a StreamCdcScan node. If the StreamNode body is neither a fragment nor an expected node shape, the validation bails with 'Unexpected node body'. This is an internal shape check protecting against frontend/meta producing a plan the CDC validation cannot understand.

Source

Thrown at src/meta/src/rpc/ddl_controller.rs:1049

                    .await?
                {
                    found_cdc_scan = true;
                }
            }
            // When there's generated columns, the cdc scan node is wrapped in a project node
            Some(NodeBody::Project(_)) => {
                for input in &stream_scan_fragment.nodes.input {
                    assert_parallelism(stream_scan_fragment.distribution_type, &input.node_body);
                    if self
                        .validate_cdc_table_inner(&input.node_body, table.id)
                        .await?
                    {
                        found_cdc_scan = true;
                    }
                }
            }
            _ => {
                bail!("Unexpected node body for stream cdc scan");
            }
        };
        if !found_cdc_scan {
            bail!("No stream cdc scan node found in stream scan fragment");
        }
        Ok(())
    }

    async fn validate_cdc_table_inner(
        &self,
        node_body: &Option<NodeBody>,
        table_id: TableId,
    ) -> MetaResult<bool> {
        if let Some(NodeBody::StreamCdcScan(stream_cdc_scan)) = node_body
            && let Some(ref cdc_table_desc) = stream_cdc_scan.cdc_table_desc
        {
            let options_with_secret = WithOptionsSecResolved::new(
                cdc_table_desc.connect_properties.clone(),

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check RisingWave component versions are consistent across frontend and meta; upgrade mismatched nodes together.
  2. Inspect the generated fragment graph to see which node body type appeared; extend validate_cdc_table to handle it if it's a new legitimate node type.
  3. Report to RisingWave maintainers if a standard CDC table creation triggers this — it indicates an internal invariant break.

Example fix

// before
_ => {
    bail!("Unexpected node body for stream cdc scan");
}
// after
StreamNodeBody::SomeNewVariant(..) => {
    // treat as scan-like body
    found_cdc_scan = found_cdc_scan || contains_cdc_scan(node);
}
_ => bail!("Unexpected node body for stream cdc scan"),
Defensive patterns

Strategy: try-catch

Type guard

fn is_cdc_scan_body(body: &StreamNodeBody) -> bool {
    matches!(body, StreamNodeBody::StreamCdcScan(..))
}

Try / catch

match create_cdc_table(...).await {
    Err(e) if e.to_string().contains("Unexpected node body for stream cdc scan") => {
        // verify frontend/meta version alignment, then report/upgrade
    }
    other => other?,
}

Prevention

When it happens

Trigger: Creating a CDC table whose generated stream scan fragment has a top-level node body variant other than the ones validate_cdc_table handles (e.g. after a plan/protobuf change or an unexpected ExternalStream/Source wrapper).

Common situations: Version skew between frontend and meta node after an upgrade; a new connector or node type added in the frontend but not yet handled in meta's CDC validation; hand-modified or corrupted fragment graphs.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/4b0e59f45bd265ee. Report an issue: GitHub.