risingwavelabs/risingwave · error

sink {} is not ready to be replaced

Error message

sink {} is not ready to be replaced

What it means

The sink being replaced must be fully created (JobStatus::Created). This error means the old streaming job's status is still Creating/Failed/Initializing, so its catalog cannot be safely replaced yet.

Source

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

                .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(
                    JoinType::InnerJoin,
                    object_dependency::Relation::Object1.def(),
                )

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Wait until the sink finishes creation (check rw_streaming_jobs / SHOW JOBS for status Created).
  2. If the sink is stuck in Creating, abort/cancel the creating job first, then replace or recreate.
  3. Retry the replace statement after the sink becomes ready.
  4. If permanently stuck, drop the sink and recreate it.
Defensive patterns

Strategy: validation

Validate before calling

-- wait until status is 'Created'
SELECT job_status FROM rw_streaming_jobs WHERE job_id = <old_sink_job_id>;

Try / catch

if let Err(e) = replace_sink(..).await {
    if e.to_string().contains("is not ready to be replaced") {
        // poll job status until Created, then retry once
    }
}

Prevention

When it happens

Trigger: CREATE SINK ... REPLACE issued while the target sink's streaming job has not finished creation (job_status != Created).

Common situations: User immediately re-runs a replace after creating the sink; sink creation stalled or failed in the background; racing DDL issued right after CREATE SINK.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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