risingwavelabs/risingwave · error · SinkError::Config

`task.target_completion_interval` requires…

Error message

`task.target_completion_interval` requires `task.serverless` to be true

What it means

`task.target_completion_interval` only tunes a serverless Snowflake task; from_btreemap rejects setting it when `task.serverless` is not true. Without serverless tasks the interval would be silently meaningless, so the connector fails fast instead.

Solutions

  1. Add `task.serverless = true` to the WITH options
  2. Remove `task.target_completion_interval` if you intend to use a regular warehouse-based task

Example fix

// before
WITH (connector='snowflake', type='upsert', with_s3=true, task.target_completion_interval='15m');
// after
WITH (connector='snowflake', type='upsert', with_s3=true, task.serverless=true, task.target_completion_interval='15m');
Defensive patterns

Strategy: validation

Validate before calling

if options.contains_key("task.target_completion_interval") && options.get("task.serverless").map(|v| v.as_str()) != Some("true") {
    return Err("task.target_completion_interval requires task.serverless = true");
}

Prevention

When it happens

Trigger: Creating a Snowflake upsert sink with `task.target_completion_interval` set while `task.serverless` is false or absent.

Common situations: Copying a serverless-task tuning snippet into a sink config that uses a regular warehouse; adding the interval option but forgetting to flip task.serverless to true.

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

Appendix: source

Thrown at src/connector/src/sink/snowflake_redshift/snowflake.rs:261

            return Err(SinkError::Config(anyhow!(
                "Snowflake upsert sinks require `with_s3 = true` so all CDC rows are loaded by the serialized COPY INTO task"
            )));
        }
        let has_upsert_task_config = config.snowflake_cdc_table_name.is_some()
            || properties.contains_key("write.target.interval.seconds")
            || config.snowflake_warehouse.is_some()
            || config.task_serverless
            || config.task_target_completion_interval.is_some();
        if config.r#type != SINK_TYPE_UPSERT && has_upsert_task_config {
            return Err(SinkError::Config(anyhow!(
                "`intermediate.table.name`, `write.target.interval.seconds`, `warehouse`, \
                 `task.serverless`, and `task.target_completion_interval` require `{}` = {}",
                SINK_TYPE_OPTION,
                SINK_TYPE_UPSERT
            )));
        }
        if config.task_target_completion_interval.is_some() && !config.task_serverless {
            return Err(SinkError::Config(anyhow!(
                "`task.target_completion_interval` requires `task.serverless` to be true"
            )));
        }
        if config.task_serverless && config.snowflake_warehouse.is_some() {
            return Err(SinkError::Config(anyhow!(
                "`task.serverless` must not be combined with `warehouse`"
            )));
        }

        // Normalize and validate authentication method
        let has_password = config.password.is_some();
        let has_file = config.private_key_file.is_some();
        let has_pem = config.private_key_pem.as_deref().is_some();

        let normalized_auth_method = match config
            .auth_method
            .as_deref()
            .map(|s| s.trim().to_ascii_lowercase())

View on GitHub (pinned to 6469eb736d)