risingwavelabs/risingwave · error

unsupported job type for replacement

Error message

unsupported job type for replacement: {job_type:?}

What it means

When building the replacement graph for a schema change, the builder only supports a fixed set of job types for wiring external downstream edges. Any other `StreamingJobType` falls into the `_` catch-all arm and bails. It indicates the replacement planner encountered a job type it has no replacement graph strategy for.

Solutions

  1. Check the job type being replaced; only supported job types can go through this replacement path — alter the pipeline or add a match arm for the new job type.
  2. Align frontend and meta versions (upgrade meta node) so the job type is recognized.
  3. As a workaround, recreate the job with the new schema instead of in-place replacement.

Example fix

// before
_ => bail!("unsupported job type for replacement: {job_type:?}"),
// after
StreamingJobType::Sink => { /* handle sink replacement like existing arms */ }
_ => bail!("unsupported job type for replacement: {job_type:?}"),
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED: &[StreamingJobType] = &[/* variants handled by replacement graph */];
if !SUPPORTED.contains(&job_type) {
    return Err(format!("job type {:?} cannot be replaced in place", job_type));
}

Type guard

fn is_replaceable(job_type: &StreamingJobType) -> bool {
    // mirror the match arms in build_replace_graph
    !matches!(job_type, StreamingJobType::Unsupported | _ /* unhandled variants */)
}

Try / catch

match alter_job(...) {
    Err(e) if e.to_string().starts_with("unsupported job type for replacement") => {
        // fall back to recreate-with-new-schema
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running a schema-change/replacement pipeline (`format_step`/`run_pipeline`) on a streaming job whose `StreamingJobType` is not one of the explicitly handled variants in the match at src/meta/src/stream/stream_graph/fragment.rs:1980.

Common situations: ALTER of a newer/less-common job kind (e.g. unusual sink or source variants) added before the meta replacement graph supported it; version skew where a frontend submits a job type the meta node doesn't handle.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/meta/src/stream/stream_graph/fragment.rs:1980

                    StreamingJobType::Source => {
                        let source_node = nodes.get_node_body().unwrap().as_source().unwrap();
                        let all_columns = source_node.column_descs().unwrap();
                        let output_mapping = gen_output_mapping(&output_columns, &all_columns)
                            .ok_or_else(|| {
                                MetaError::invalid_parameter(
                                    "unable to drop the column due to \
                                     being referenced by downstream materialized views or sinks",
                                )
                            })?;
                        assert_eq!(*dispatcher_type, DispatcherType::NoShuffle);
                        (
                            vec![], // not used for `NoShuffle`
                            output_mapping,
                        )
                    }

                    _ => bail!("unsupported job type for replacement: {job_type:?}"),
                };

                let edge = StreamFragmentEdge {
                    id: EdgeId::DownstreamExternal(DownstreamExternalEdgeId {
                        original_upstream_fragment_id: original_table_fragment_id,
                        downstream_fragment_id: id,
                    }),
                    dispatch_strategy: DispatchStrategy {
                        r#type: *dispatcher_type as i32,
                        output_mapping: Some(output_mapping),
                        dist_key_indices,
                    },
                };

                extra_downstreams
                    .entry(table_fragment_id)
                    .or_insert_with(HashMap::new)
                    .try_insert(id, edge.clone())

View on GitHub (pinned to 6469eb736d)