dbt-labs/dbt-core · error

'primary_key' has a wrong type in StaticBaseRelationObject:

Error message

'primary_key' has a wrong type in StaticBaseRelationObject: '{primary_key}'

What it means

`scd_args` accepts a `primary_key` that is either a list/iterable of columns or a single string. If the value is any other type (e.g. a dict, boolean, or number), the dispatcher raises this InvalidOperation error including the offending value's string form.

Source

Thrown at crates/dbt-adapter/src/relation/relation_object.rs:877

        )
    }

    fn scd_args(&self, args: &[Value]) -> Result<Value, minijinja::Error> {
        let iter = ArgsIter::new("Relation.scd_args", &[], args);
        let primary_key = iter.next_kwarg::<Value>("primary_key")?;
        let updated_at = iter.next_kwarg::<String>("updated_at")?;
        iter.finish()?;

        let mut scd_args = vec![];
        match primary_key.kind() {
            ValueKind::Seq => {
                scd_args.extend(primary_key.try_iter()?.enumerate().map(|s| s.1.to_string()));
            }
            ValueKind::String => {
                scd_args.push(primary_key.as_str().unwrap().to_string());
            }
            _ => {
                return Err(minijinja::Error::new(
                    minijinja::ErrorKind::InvalidOperation,
                    format!(
                        "'primary_key' has a wrong type in StaticBaseRelationObject: '{primary_key}'"
                    ),
                ));
            }
        }
        scd_args.push(updated_at);
        Ok(Value::from(scd_args))
    }
}

#[cfg(test)]
mod tests {
    use crate::relation::factory::create_static_relation;

    use super::*;
    use dbt_schemas::schemas::relations::DEFAULT_RESOLVED_QUOTING;

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Ensure `unique_key`/`primary_key` in the snapshot config is a string or a list of strings.
  2. Coerce the value before calling: wrap a single column as a one-element list or `| string`.
  3. Inspect the printed `{primary_key}` in the message to see the actual value and fix its source config.

Example fix

// before
{{ relation.scd_args(config.model.unique_key) }}  // unique_key is a dict
// after
{% set pk = config.model.unique_key %}
{% if pk is not string and pk is not sequence %}
  {% set pk = [pk | string] %}
{% endif %}
{{ relation.scd_args(pk) }}
Defensive patterns

Strategy: validation

Validate before calling

{% set pk = config.get('unique_key') %}
{% if pk is string or pk is sequence and pk is not string %}
  {{ relation.scd_args(pk) }}
{% else %}
  {% do exceptions.raise_compiler_error('unique_key must be a string or list of strings') %}
{% endif %}

Type guard

{% macro is_valid_pk(pk) %}
  {{ return(pk is string or (pk is sequence and pk is not mapping and pk is not string)) }}
{% endmacro %}

Prevention

When it happens

Trigger: Calling `relation.scd_args(...)` (snapshot SCD argument building) where the `primary_key` argument resolves to a non-string, non-list Jinja value — e.g. a dict from `config.get('unique_key')` or a boolean.

Common situations: Snapshot configs where `unique_key` is a dict or None-derived value instead of a string or list of strings; macros passing `config.model.unique_key` through unmodified when it has an unexpected shape.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/d98bf79edd235885. Report an issue: GitHub.