dbt-labs/dbt-core · error · AdapterError

'{strategy}' strategy does not support unique_key.

Error message

'{strategy}' strategy does not support unique_key.

What it means

insert_overwrite replaces entire partitions, so per-row key matching via unique_key is incompatible with it on ClickHouse. validate_incremental_strategy raises this Configuration error when insert_overwrite is combined with a unique_key config.

Source

Thrown at crates/dbt-adapter/src/metadata/clickhouse/mod.rs:927

        ));
    }
    if matches!(strategy, "delete_insert" | "microbatch") && !has_unique_key {
        return err(format!(
            "'{strategy}' strategy requires a non-empty 'unique_key'."
        ));
    }
    if !matches!(strategy, "delete_insert" | "microbatch") && has_predicates {
        return err(format!(
            "Cannot apply incremental predicates with '{strategy}' strategy."
        ));
    }
    if strategy == "insert_overwrite" && !has_partition_by {
        return err(format!(
            "'{strategy}' strategy requires non-empty 'partition_by'. Current partition_by is None."
        ));
    }
    if strategy == "insert_overwrite" && has_unique_key {
        return err(format!(
            "'{strategy}' strategy does not support unique_key."
        ));
    }
    Ok(())
}

/// Mirrors column.py `ClickHouseColumnChanges` as a Jinja value: none when
/// there are no changes (its `__bool__`, so `{% if column_changes %}` skips),
/// else a map; errors when the strategy cannot reconcile the changes.
pub(crate) fn column_changes_value(
    on_schema_change: &str,
    source: Vec<Column>,
    target: Vec<Column>,
    materialization: &str,
) -> AdapterResult<Value> {
    let in_target = |name: &str| target.iter().any(|c| c.name() == name);
    let source_of = |name: &str| source.iter().find(|c| c.name() == name);

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Remove unique_key from the model config when using insert_overwrite
  2. Use partition_by to scope which data gets replaced instead
  3. If per-key upsert semantics are needed, switch back to delete_insert and keep unique_key

Example fix

// before
{{ config(materialized='incremental', incremental_strategy='insert_overwrite', partition_by='toDate(event_ts)', unique_key='id') }}
// after
{{ config(materialized='incremental', incremental_strategy='insert_overwrite', partition_by='toDate(event_ts)') }}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.incremental_strategy == "insert_overwrite" && cfg.unique_key.is_some() {
    panic!("unique_key is incompatible with insert_overwrite");
}

Prevention

When it happens

Trigger: Setting incremental_strategy='insert_overwrite' together with unique_key on a ClickHouse incremental model — usually left over from a previous delete_insert/delete+insert configuration.

Common situations: Flipping incremental_strategy from delete_insert to insert_overwrite without removing unique_key; a shared macro/base config injecting unique_key for all incremental models.

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 dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/25154827801cf6bb. Report an issue: GitHub.