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
- Check RisingWave component versions are consistent across frontend and meta; upgrade mismatched nodes together.
- 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.
- 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
- Keep frontend and meta node versions in lockstep
- After upgrades, test CDC table creation before production use
- Capture the fragment graph when reporting the bug
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
- PostgreSQL schema `{schema}` does not exist
- PostgreSQL table `{schema}`.`{table}` does not exist
- cannot find field type for {}
- source validation failed
- invalid backfill_num_rows_per_split, must be greater than 0
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/4b0e59f45bd265ee.
Report an issue: GitHub.