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_type

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Create the sink directly over a table/backfill arrangement without intermediate operators if schema refresh is required.
  2. Verify the sink's upstream is a table with backfill; auto refresh-schema only supports the StreamScan(ArrangementBackfill) shape.
  3. Align frontend/meta versions and retry the DDL.
  4. 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

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


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