risingwavelabs/risingwave · error
expect PbNodeBody::StreamScan or PbNodeBody::Project but got
Error message
expect PbNodeBody::StreamScan or PbNodeBody::Project but got: {:?} What it means
In `check_sink_fragments_support_refresh_schema`, after the sink node the code expects the next node to be either a StreamScan or a Project (Project being the schema-change indirection). Any other node body variant reaches this catch-all branch and produces this error, meaning the sink fragment topology is not one of the shapes the auto-refresh-schema feature understands.
Source
Thrown at src/meta/src/stream/stream_graph/fragment.rs:428
return Err(anyhow!("expect PbNodeBody::Sink but got: {:?}", sink_node.node_body).into());
};
let [stream_input_node] = sink_node.input.as_slice() else {
panic!("Sink has more than 1 input: {:?}", sink_node.input);
};
let stream_scan_node = match stream_input_node.node_body.as_ref().unwrap() {
PbNodeBody::StreamScan(_) => stream_input_node,
PbNodeBody::Project(_) => {
let [stream_scan_node] = stream_input_node.input.as_slice() else {
return Err(anyhow!(
"Project node must have exactly 1 input for auto schema change, but got {:?}",
stream_input_node.input.len()
)
.into());
};
stream_scan_node
}
_ => {
return Err(anyhow!(
"expect PbNodeBody::StreamScan or PbNodeBody::Project but got: {:?}",
stream_input_node.node_body
)
.into());
}
};
let PbNodeBody::StreamScan(scan) = stream_scan_node.node_body.as_ref().unwrap() else {
return Err(anyhow!(
"expect PbNodeBody::StreamScan but got: {:?}",
stream_scan_node.node_body
)
.into());
};
let stream_scan_type = PbStreamScanType::try_from(scan.stream_scan_type).unwrap();
if stream_scan_type != PbStreamScanType::ArrangementBackfill {
return Err(anyhow!(
"unsupported stream_scan_type for auto refresh schema: {:?}",
stream_scan_typeView on GitHub (pinned to 6469eb736d)
Solutions
- Create the sink directly over a table/backfill arrangement without intermediate operators if schema refresh is required.
- Verify the sink's upstream is a table with backfill; auto refresh-schema only supports the StreamScan(ArrangementBackfill) shape.
- Align frontend/meta versions and retry the DDL.
- If supported SQL still triggers it, file a RisingWave bug with the job definition.
Example fix
// before
_ => { return Err(anyhow!("expect PbNodeBody::StreamScan or PbNodeBody::Project but got: {:?}", ...).into()); }
// after: skip validation for unsupported shapes instead of failing job creation
_ => { tracing::info!("sink fragment shape {:?} not eligible for refresh schema; skipping", stream_input_node.node_body); return Ok(()); } Defensive patterns
Strategy: validation
Validate before calling
match stream_input_node.node_body.as_ref() {
Some(PbNodeBody::StreamScan(_) | PbNodeBody::Project(_)) => {},
other => return Err(format!("unsupported sink input for refresh schema: {:?}", other)),
} Type guard
fn supports_refresh_schema(node: &StreamNode) -> bool {
matches!(node.node_body.as_ref(), Some(PbNodeBody::StreamScan(_) | PbNodeBody::Project(_)))
} Prevention
- Create sinks directly over tables/backfill scans when schema refresh is needed.
- Check the feature's supported topology docs before enabling auto schema change.
- Test schema evolution flows in staging after version upgrades.
When it happens
Trigger: `generate_streaming_job` -> `check_sink_fragments_support_refresh_schema` where the sink's single input node has a `node_body` other than `PbNodeBody::StreamScan` or `PbNodeBody::Project` (e.g. Exchange, Filter, TopN).
Common situations: Creating a sink over a materialized view or query whose streaming graph inserts extra operators (filters, transforms) between the sink and the backfill scan, then relying on auto schema refresh; plan layout changes across RisingWave versions.
Related errors
- expect PbNodeBody::Sink but got: {:?}
- Project node must have exactly 1 input for auto schema chang
- expect PbNodeBody::Merge but got: {:?}
- expect PbNodeBody::Project but got: {:?}
- expect PbNodeBody::StreamScan but got: {:?}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c538da4e17d86ee4.
Report an issue: GitHub.