risingwavelabs/risingwave · error · SinkError::Coordinator

Schema change is not implemented for two-phase commit coordi

Error message

Schema change is not implemented for two-phase commit coordinator {}

What it means

Identical to the single-phase variant but on the two-phase commit coordinator trait: the default `commit_schema_change` implementation always returns this error, meaning the sink connector does not support committing schema evolution during the two-phase commit protocol.

Source

Thrown at src/connector/src/sink/mod.rs:1005

    /// Return serialized commit metadata to be passed to `commit`.
    async fn pre_commit(
        &mut self,
        epoch: u64,
        metadata: Vec<SinkMetadata>,
        schema_change: Option<PbSinkSchemaChange>,
    ) -> Result<Option<Vec<u8>>>;

    /// Idempotent implementation is required, because `commit_data` in the same epoch could be called multiple times.
    async fn commit_data(&mut self, epoch: u64, commit_metadata: Vec<u8>) -> Result<()>;

    /// Idempotent implementation is required, because `commit_schema_change` in the same epoch could be called multiple
    /// times.
    async fn commit_schema_change(
        &mut self,
        _epoch: u64,
        _schema_change: PbSinkSchemaChange,
    ) -> Result<()> {
        Err(SinkError::Coordinator(anyhow!(
            "Schema change is not implemented for two-phase commit coordinator {}",
            std::any::type_name::<Self>()
        )))
    }

    /// Idempotent implementation is required, because `abort` in the same epoch could be called multiple times.
    async fn abort(&mut self, epoch: u64, commit_metadata: Vec<u8>);
}

impl SinkImpl {
    pub fn new(mut param: SinkParam) -> Result<Self> {
        const PRIVATE_LINK_TARGET_KEY: &str = "privatelink.targets";

        // remove privatelink related properties if any
        param.properties.remove(PRIVATE_LINK_TARGET_KEY);

        let sink_type = param
            .properties

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Defer schema changes until the sink is recreated with the new schema
  2. Switch to a sink connector that implements schema-change commit in its two-phase coordinator
  3. Implement `commit_schema_change` in the connector's coordinator if you own the connector
Defensive patterns

Strategy: try-catch

Try / catch

match err {
    SinkError::Coordinator(e) if e.to_string().contains("two-phase commit coordinator") => {
        // handle: pause sink, recreate with new schema, resume
    }
    e => return Err(e.into()),
}

Prevention

When it happens

Trigger: A `PbSinkSchemaChange` is committed at an epoch against a two-phase commit coordinator (sink decouple enabled) whose type only provides the default `commit_schema_change`, i.e. any connector that has not overridden it (typically triggered by upstream schema alterations).

Common situations: Running an ALTER on the source/mv feeding an Iceberg-style decoupled sink with a connector lacking schema evolution; misjudging which connectors support schema-change commit.

Related errors


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