{"record":{"id":"25154827801cf6bb","repo":"dbt-labs/dbt-core","slug":"strategy-strategy-does-not-support-unique-key","errorCode":null,"errorMessage":"'{strategy}' strategy does not support unique_key.","messagePattern":"'(.+?)' strategy does not support unique_key\\.","errorType":"validation","errorClass":"AdapterError","httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/metadata/clickhouse/mod.rs","lineNumber":927,"sourceCode":"        ));\n    }\n    if matches!(strategy, \"delete_insert\" | \"microbatch\") && !has_unique_key {\n        return err(format!(\n            \"'{strategy}' strategy requires a non-empty 'unique_key'.\"\n        ));\n    }\n    if !matches!(strategy, \"delete_insert\" | \"microbatch\") && has_predicates {\n        return err(format!(\n            \"Cannot apply incremental predicates with '{strategy}' strategy.\"\n        ));\n    }\n    if strategy == \"insert_overwrite\" && !has_partition_by {\n        return err(format!(\n            \"'{strategy}' strategy requires non-empty 'partition_by'. Current partition_by is None.\"\n        ));\n    }\n    if strategy == \"insert_overwrite\" && has_unique_key {\n        return err(format!(\n            \"'{strategy}' strategy does not support unique_key.\"\n        ));\n    }\n    Ok(())\n}\n\n/// Mirrors column.py `ClickHouseColumnChanges` as a Jinja value: none when\n/// there are no changes (its `__bool__`, so `{% if column_changes %}` skips),\n/// else a map; errors when the strategy cannot reconcile the changes.\npub(crate) fn column_changes_value(\n    on_schema_change: &str,\n    source: Vec<Column>,\n    target: Vec<Column>,\n    materialization: &str,\n) -> AdapterResult<Value> {\n    let in_target = |name: &str| target.iter().any(|c| c.name() == name);\n    let source_of = |name: &str| source.iter().find(|c| c.name() == name);\n","sourceCodeStart":909,"sourceCodeEnd":945,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/metadata/clickhouse/mod.rs#L909-L945","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove unique_key from the model config when using insert_overwrite","Use partition_by to scope which data gets replaced instead","If per-key upsert semantics are needed, switch back to delete_insert and keep unique_key"],"exampleFix":"// before\n{{ config(materialized='incremental', incremental_strategy='insert_overwrite', partition_by='toDate(event_ts)', unique_key='id') }}\n// after\n{{ config(materialized='incremental', incremental_strategy='insert_overwrite', partition_by='toDate(event_ts)') }}","handlingStrategy":"validation","validationCode":"if cfg.incremental_strategy == \"insert_overwrite\" && cfg.unique_key.is_some() {\n    panic!(\"unique_key is incompatible with insert_overwrite\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remove unique_key when switching to insert_overwrite","Avoid shared config macros that inject unique_key unconditionally","Model partition-level replacement intent with partition_by, not keys"],"tags":["clickhouse","dbt","configuration","conflicting-options"],"backgroundTag":"conflicting-config-options","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}