dbt-labs/dbt-core · warning
Invalid primary key column: {column_name}
Error message
Invalid primary key column: {column_name} What it means
A warning raised by the Databricks primary_key constraint macro when a column name listed in the constraint's `columns` (or the column-level constraint's own name) does not exist in the model's `columns` dictionary. The macro looks up `model['columns'][column_name]`; a miss means the ALTER TABLE ... PRIMARY KEY statement would reference a nonexistent column, so that column is skipped and warned about. Compilation still succeeds.
Source
Thrown at crates/dbt-loader/src/dbt_macro_assets/dbt-databricks/macros/relations/constraints.sql:195
{% set stmt = "alter table " ~ relation.render() ~ " change column " ~ quoted_name ~ " set not null " ~ (constraint.expression or "") ~ ";" %}
{% do statements.append(stmt) %}
{% else %}
{{ exceptions.warn('not_null constraint on invalid column: ' ~ column_name) }}
{% endif %}
{% endfor %}
{% elif type == 'primary_key' %}
{% if constraint.get('warn_unenforced') %}
{{ exceptions.warn("unenforced constraint type: " ~ type)}}
{% endif %}
{% set column_names = constraint.get('columns', []) %}
{% if column and not column_names %}
{% set column_names = [column['name']] %}
{% endif %}
{% set quoted_names = [] %}
{% for column_name in column_names %}
{% set column = model.get('columns', {}).get(column_name) %}
{% if not column %}
{{ exceptions.warn('Invalid primary key column: ' ~ column_name) }}
{% else %}
{% set quoted_name = adapter.quote(column['name']) %}
{% do quoted_names.append(quoted_name) %}
{% endif %}
{% endfor %}
{% set joined_names = quoted_names|join(", ") %}
{% set pk_expression = constraint.get('expression') %}
{% set name = constraint.get('name') %}
{% if not name %}
{% if local_md5 %}
{{ exceptions.warn("Constraint of type " ~ type ~ " with no `name` provided. Generating hash instead for relation " ~ relation.identifier) }}
{%- set hash_input = "primary_key;" ~ relation.identifier ~ ";" ~ column_names ~ ";" -%}
{%- if pk_expression -%}
{%- set hash_input = hash_input ~ pk_expression ~ ";" -%}
{%- endif -%}
{%- set name = local_md5(hash_input) -%}View on GitHub (pinned to 0267ce9170)
Solutions
- Fix the column name in the constraint so it exactly matches a key under `columns:` in the model's YAML.
- Add the missing column definition (name plus any properties) under the model's `columns:` in schema.yml.
- Check case sensitivity: Databricks column names in YAML must match exactly as declared.
- Remove the stale column from the constraint's `columns` list if the column was dropped.
Example fix
// before (schema.yml)
columns:
- name: user_id
constraints:
- type: primary_key
columns: [userId]
// after
constraints:
- type: primary_key
columns: [user_id] Defensive patterns
Strategy: validation
Validate before calling
// pre-run schema validation (Python)
import yaml
cfg = yaml.safe_load(open('models/schema.yml'))
for m in cfg['models']:
cols = {c['name'] for c in m.get('columns', [])}
for c in m.get('constraints', []):
if c['type'] == 'primary_key':
missing = [n for n in c.get('columns', []) if n not in cols]
assert not missing, f"{m['name']}: PK columns not in columns: {missing}" Type guard
def has_column(model: dict, col: str) -> bool:
return col in model.get('columns', {}) Prevention
- Keep every constrained column declared under columns: in schema.yml.
- Run dbt parse / dbt compile in CI and grep logs for 'Invalid primary key column'.
- Use schema validation (dbt-jsonschema / schemaspy) to catch mismatches early.
- Update constraints whenever columns are renamed or removed.
When it happens
Trigger: A `primary_key` constraint references a column name that is misspelled, not defined under `columns:` in the model's YAML (schema.yml), or differs in case from the declared column; the lookup `model.get('columns', {}).get(column_name)` at constraints.sql:193 returns nothing.
Common situations: Typo in the constraint `columns` list; declaring a column-level PK constraint in dbt_project.yml or config instead of schema.yml so the column context is missing; renaming a column without updating the constraint; relying on columns inferred only from SQL (constraints need explicit `columns:` entries in YAML for this lookup).
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- unenforced constraint type: {type}
- unenforced constraint type: {constraint.type}
- Constraint of type {{ type }} with no `name` provided. Gener
- Constraints not supported for file format: {adapter.resolve_
- Constraint of type {type} with no `name` provided. Generatin
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/37c0b2a7971e84a7.
Report an issue: GitHub.