risingwavelabs/risingwave · error

No stream cdc scan node found in stream scan fragment

Error message

No stream cdc scan node found in stream scan fragment

What it means

validate_cdc_table walks the stream scan fragment looking for a StreamCdcScan node and fails if none is found. This means the plan generated for a CDC table lacks the required CDC scan operator, so meta refuses to create the streaming job rather than build a table that cannot consume CDC events.

Solutions

  1. Verify frontend and meta are the same version and rebuild/redeploy consistently.
  2. Check the generated plan (EXPLAIN or fragment view) to confirm whether a cdc scan exists upstream; fix the source/connector definition.
  3. If triggered by a code change, extend or correct the plan so the CDC table includes a StreamCdcScan node.

Example fix

// before: validating an arbitrary scan fragment without a cdc scan node
// after: ensure the table is created with a proper CDC source so the plan contains StreamCdcScan
CREATE TABLE t (...) WITH (
   connector = 'cdc-postgres', ...
) FROM pg_source;
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = create_cdc_table(...).await {
    if e.to_string().contains("No stream cdc scan node found") {
        // check source is a proper CDC source and versions match
    }
}

Prevention

When it happens

Trigger: Creating a CDC table where the stream scan fragment contains no StreamCdcScan node — e.g. the frontend produced a wrong plan for the CDC source, or validation is applied to a fragment type that never contains a cdc scan.

Common situations: Bugs in CDC plan generation after frontend changes; applying a CDC table on a source that got rewritten to a different operator; version mismatch between frontend and meta binaries.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

            }
            // 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(),
                cdc_table_desc.secret_refs.clone(),
            );

            let mut props = ConnectorProperties::extract(options_with_secret, true)?;

View on GitHub (pinned to 6469eb736d)