{"record":{"id":"b9f02a48b86e02ce","repo":"risingwavelabs/risingwave","slug":"sink-is-not-ready-to-be-replaced","errorCode":null,"errorMessage":"sink {} is not ready to be replaced","messagePattern":"sink (.+?) is not ready to be replaced","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/controller/streaming_job.rs","lineNumber":531,"sourceCode":"                .one(&txn)\n                .await?\n                .ok_or_else(|| MetaError::catalog_id_not_found(\"sink\", *old_sink_id))?;\n            if old_object.obj_type != ObjectType::Sink\n                || old_object.database_id != Some(sink.database_id)\n                || old_object.schema_id != Some(sink.schema_id)\n                || old_sink.name != sink.name\n            {\n                bail!(\n                    \"old sink {} does not match replacement sink {}\",\n                    old_sink_id,\n                    sink.name\n                );\n            }\n            if old_sink.target_table.is_some() || sink.target_table.is_some() {\n                bail!(\"replace sink into table is not supported\");\n            }\n            if old_streaming_job.job_status != JobStatus::Created {\n                bail!(\"sink {} is not ready to be replaced\", old_sink_id);\n            }\n        } else {\n            check_relation_name_duplicate(\n                &streaming_job.name(),\n                streaming_job.database_id(),\n                streaming_job.schema_id(),\n                &txn,\n            )\n            .await?;\n        }\n\n        // check if any dependency is in altering status.\n        if !dependencies.is_empty() {\n            let altering_cnt = ObjectDependency::find()\n                .join(\n                    JoinType::InnerJoin,\n                    object_dependency::Relation::Object1.def(),\n                )","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/controller/streaming_job.rs#L513-L549","documentation":"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.","triggerScenarios":"CREATE SINK ... REPLACE issued while the target sink's streaming job has not finished creation (job_status != Created).","commonSituations":"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.","solutions":["Wait until the sink finishes creation (check rw_streaming_jobs / SHOW JOBS for status Created).","If the sink is stuck in Creating, abort/cancel the creating job first, then replace or recreate.","Retry the replace statement after the sink becomes ready.","If permanently stuck, drop the sink and recreate it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- wait until status is 'Created'\nSELECT job_status FROM rw_streaming_jobs WHERE job_id = <old_sink_job_id>;","typeGuard":null,"tryCatchPattern":"if let Err(e) = replace_sink(..).await {\n    if e.to_string().contains(\"is not ready to be replaced\") {\n        // poll job status until Created, then retry once\n    }\n}","preventionTips":["Gate replace DDL on job readiness in tooling","Handle stuck Creating jobs (abort) before replacing"],"tags":["meta","sink","replace","job-status"],"backgroundTag":"invalid-state-transition","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}