risingwavelabs/risingwave · error · SinkError::Config

`enable_pk_index` is only supported for upsert iceberg sink

Error message

`enable_pk_index` is only supported for upsert iceberg sink with format version >= 2

What it means

This error is raised when `enable_pk_index = true` is set on an upsert merge-on-read Iceberg sink whose `format_version` is below 2. Positional-delete/index structures used by the pk index require Iceberg format v2 features; v1 tables cannot represent them, so the config is rejected in `validate_enable_pk_index` (src/connector/src/sink/iceberg/config.rs:556).

Source

Thrown at src/connector/src/sink/iceberg/config.rs:557

    pub(crate) fn validate_enable_pk_index(&self) -> Result<()> {
        if !self.enable_pk_index {
            return Ok(());
        }

        if self.r#type != SINK_TYPE_UPSERT {
            return Err(SinkError::Config(anyhow!(
                "`enable_pk_index` is only supported for upsert iceberg sink"
            )));
        }

        if self.write_mode != IcebergWriteMode::MergeOnRead {
            return Err(SinkError::Config(anyhow!(
                "`enable_pk_index` is only supported for upsert iceberg sink with merge-on-read mode"
            )));
        }

        if self.format_version < FormatVersion::V2 {
            return Err(SinkError::Config(anyhow!(
                "`enable_pk_index` is only supported for upsert iceberg sink with format version >= 2"
            )));
        }

        if self.force_append_only {
            return Err(SinkError::Config(anyhow!(
                "`enable_pk_index` cannot be true when `force_append_only` is true"
            )));
        }

        Ok(())
    }

    pub fn from_btreemap(values: BTreeMap<String, String>) -> Result<Self> {
        let mut config =
            serde_json::from_value::<IcebergConfig>(serde_json::to_value(&values).unwrap())
                .map_err(|e| SinkError::Config(anyhow!(e)))?;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Set `format_version = 2` in the sink WITH options.
  2. If the target Iceberg table is v1 and cannot be upgraded, remove `enable_pk_index` and supply an explicit `primary-key` instead.
  3. Migrate the target table/catalog to format v2 if v1 is only a historical default.

Example fix

-- before
WITH (
  connector = 'iceberg',
  type = 'upsert',
  write_mode = 'merge-on-read',
  format_version = 1,
  enable_pk_index = true
);

-- after
WITH (
  connector = 'iceberg',
  type = 'upsert',
  write_mode = 'merge-on-read',
  format_version = 2,
  enable_pk_index = true
);
Defensive patterns

Strategy: validation

Validate before calling

-- pin format_version = 2 whenever enable_pk_index = true
WITH (connector='iceberg', type='upsert', write_mode='merge-on-read', format_version=2, enable_pk_index=true)

Try / catch

-- config errors surface at CREATE SINK time; correct format_version and re-run

Prevention

When it happens

Trigger: Creating an Iceberg upsert sink with `enable_pk_index = true`, `write_mode = 'merge-on-read'`, but `format_version = 1` (or omitted where the default resolves below v2). Fails at sink config validation.

Common situations: Writing to legacy Iceberg tables pinned to format v1; older table templates or existing catalogs created before v2 became standard; users unaware the pk index depends on v2 delete semantics.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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