risingwavelabs/risingwave · error

replace sink into table is not supported

Error message

replace sink into table is not supported

What it means

Guard in create_job_catalog during sink replacement (`ALTER ... REPLACE`): the object being replaced is configured as a sink-into-table replacement, which the meta service does not support, so job catalog creation for the replacement fails.

Source

Thrown at src/meta/src/controller/streaming_job.rs:528

                .and_then(|(sink, object)| object.map(|object| (sink, object)))
                .ok_or_else(|| MetaError::catalog_id_not_found("sink", *old_sink_id))?;
            let old_streaming_job = StreamingJobModel::find_by_id(old_sink_id.as_job_id())
                .one(&txn)
                .await?
                .ok_or_else(|| MetaError::catalog_id_not_found("sink", *old_sink_id))?;
            if old_object.obj_type != ObjectType::Sink
                || old_object.database_id != Some(sink.database_id)
                || old_object.schema_id != Some(sink.schema_id)
                || old_sink.name != sink.name
            {
                bail!(
                    "old sink {} does not match replacement sink {}",
                    old_sink_id,
                    sink.name
                );
            }
            if old_sink.target_table.is_some() || sink.target_table.is_some() {
                bail!("replace sink into table is not supported");
            }
            if old_streaming_job.job_status != JobStatus::Created {
                bail!("sink {} is not ready to be replaced", old_sink_id);
            }
        } else {
            check_relation_name_duplicate(
                &streaming_job.name(),
                streaming_job.database_id(),
                streaming_job.schema_id(),
                &txn,
            )
            .await?;
        }

        // check if any dependency is in altering status.
        if !dependencies.is_empty() {
            let altering_cnt = ObjectDependency::find()
                .join(

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Drop the sink-into-table sink and create the new sink separately instead of using REPLACE.
  2. Ensure both old and new sinks are external (non-table-target) sinks when using replace.
  3. Split the operation: drop old sink, then CREATE SINK INTO TABLE if that is the goal.
Defensive patterns

Strategy: validation

Validate before calling

-- check the old sink is not sink-into-table
SELECT s.target_table IS NOT NULL AS into_table
FROM rw_sinks s WHERE s.id = <old_sink_id>;

Try / catch

if let Err(e) = catalog.create_job_catalog(job).await {
    if e.to_string().contains("replace sink into table is not supported") {
        // fall back to DROP SINK + CREATE SINK
    }
}

Prevention

When it happens

Trigger: create_job_catalog with replace_sink where old_sink.target_table is Some or the new sink's target_table is Some.

Common situations: User attempts CREATE SINK ... REPLACE on a sink created with `INTO table`, or replaces a plain sink with a sink-into-table sink.

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/ccb998134961a1d7. Report an issue: GitHub.