risingwavelabs/risingwave · error · SinkError

only iceberg table can be altered as sink

Error message

only iceberg table can be altered as sink

What it means

In `update_iceberg_table_props_by_table_id`, the definition is parsed and must be a `CREATE TABLE ... ENGINE = ICEBERG` statement (an iceberg table associated with a sink). If the parsed statement's engine is not Iceberg, the controller rejects the alter with `SinkError::Config("only iceberg table can be altered as sink")`. This path only supports on-the-fly property changes for iceberg tables created via `CREATE TABLE ... WITH (SINK)`.

Source

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

            .find_also_related(Object)
            .one(&txn)
            .await?
            .ok_or_else(|| MetaError::catalog_id_not_found(ObjectType::Sink.as_str(), sink_id))?;
        validate_sink_props(&sink, &props)?;

        let definition = sink.definition.clone();
        let [mut stmt]: [_; 1] = Parser::parse_sql(&definition)
            .map_err(|e| SinkError::Config(anyhow!(e)))?
            .try_into()
            .unwrap();
        if let Statement::CreateTable {
            with_options,
            engine,
            ..
        } = &mut stmt
        {
            if !matches!(engine, Engine::Iceberg) {
                return Err(SinkError::Config(anyhow!(
                    "only iceberg table can be altered as sink"
                ))
                .into());
            }
            update_stmt_with_props(with_options, &props)?;
        } else {
            panic!("definition is not a create iceberg table statement")
        }
        let mut new_config = sink.properties.clone().into_inner();
        new_config.extend(props.clone());

        let definition = stmt.to_string();
        let active_sink = sink::ActiveModel {
            sink_id: Set(sink_id),
            properties: Set(risingwave_meta_model::Property(new_config.clone())),
            definition: Set(definition.clone()),
            ..Default::default()
        };

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Confirm the target table is an iceberg table created with `CREATE TABLE ... WITH (SINK ...) ENGINE = ICEBERG`.
  2. Use the regular sink alter path (ALTER SINK) for non-iceberg sinks instead of the iceberg-table alter API.
  3. Check that the sink_id/table_id pair passed in PbExtraOptions::AlterIcebergTableIds refers to the iceberg table's associated sink.
  4. If you need iceberg semantics, recreate the table as an iceberg table.

Example fix

-- before: ALTER on a non-iceberg table
ALTER TABLE t ALTER CONNECTOR PROPS (...); -- errors
-- after: only iceberg tables
ALTER TABLE iceberg_t WITH (SINK ...) ENGINE = ICEBERG; -- then alter its props
Defensive patterns

Strategy: validation

Validate before calling

-- ensure the table is an iceberg table before altering as sink
SELECT engine FROM rw_tables WHERE name = 'my_table'; -- must be 'iceberg'

Prevention

When it happens

Trigger: Calling the iceberg-table property alter API (update_iceberg_table_props_by_table_id) against a table whose definition declares an engine other than Iceberg, or which is a regular non-iceberg table.

Common situations: Passing a table_id of a normal (non-iceberg) table to the iceberg alter endpoint; attempting to alter connector props on a table that was not created with `ENGINE = ICEBERG` / sink-to-iceberg; client-side routing that sends the wrong table id.

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