dbt-labs/dbt-core · warning

Constraint of type {{ type }} with no `name` provided. Gener

Error message

Constraint of type {{ type }} with no `name` provided. Generating hash instead for relation {{ relation.identifier }}

What it means

Like error 787 but on the foreign_key-with-expression path: when a foreign_key constraint supplies an `expression` (e.g. `(id) references parent(id)`) but no `name`, and `local_md5` is available, the macro warns and generates the constraint name as `md5("foreign_key;<identifier>;<expression>;")`. Without md5 it would instead raise a compiler error; here compilation succeeds with a hash name.

Source

Thrown at crates/dbt-loader/src/dbt_macro_assets/dbt-databricks/macros/relations/constraints.sql:233

        {{ exceptions.raise_compiler_error("Constraint of type " ~ type ~ " with no `name` provided, and no md5 utility.") }}
      {% endif %}
    {% endif %}
    {% set pk_suffix = (" " ~ pk_expression) if pk_expression else "" %}
    {% set stmt = "alter table " ~ relation.render() ~ " add constraint " ~ name ~ " primary key(" ~ joined_names ~ ")" ~ pk_suffix ~ ";" %}
    {% do statements.append(stmt) %}
  {% elif type == 'foreign_key' %}

    {% if constraint.get('warn_unenforced') %}
      {{ exceptions.warn("unenforced constraint type: " ~ constraint.type)}}
    {% endif %}

    {% set name = constraint.get('name') %}
    
    {% if constraint.get('expression') %}

      {% if not name %}
        {% if local_md5 %}
          {{ exceptions.warn("Constraint of type " ~ type ~ " with no `name` provided. Generating hash instead for relation " ~ relation.identifier) }}
          {%- set name = local_md5("foreign_key;" ~ relation.identifier ~ ";" ~ constraint.get('expression') ~ ";") -%}
        {% else %}
          {{ exceptions.raise_compiler_error("Constraint of type " ~ type ~ " with no `name` provided, and no md5 utility.") }}
        {% endif %}    
      {% endif %}

      {% set stmt = "alter table " ~ relation.render() ~ " add constraint " ~ name ~ " foreign key" ~ constraint.get('expression') %}
    {% else %}
      {% 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 foreign key column: ' ~ column_name) }}
        {% else %}

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Add an explicit `name` field to the foreign_key constraint for a stable, readable name.
  2. Accept the warning; the md5-derived name is deterministic for identical identifier+expression.
  3. If the generated name changes when the expression is edited, pin a `name` to keep the constraint identity stable across refactors.
  4. Ensure the adapter exposes local_md5 — if it is missing this same condition raises a compiler error instead.

Example fix

// before
- type: foreign_key
  expression: "(user_id) REFERENCES parent(id)"
// after
- type: foreign_key
  name: fk_child_user
  expression: "(user_id) REFERENCES parent(id)"
Defensive patterns

Strategy: validation

Validate before calling

import yaml
cfg = yaml.safe_load(open('models/schema.yml'))
for m in cfg['models']:
    for c in m.get('constraints', []):
        if c['type'] == 'foreign_key' and c.get('expression') and not c.get('name'):
            raise ValueError(f"foreign_key constraint on {m['name']} needs a name")

Type guard

def fk_is_named(c: dict) -> bool:
    return not c.get('expression') or bool(c.get('name'))

Prevention

When it happens

Trigger: A foreign_key constraint with `expression` set but `name` omitted, processed at constraints.sql:231-234 while `local_md5` exists; e.g. `constraints: [{type: foreign_key, expression: "(user_id) REFERENCES schema.parent(id)"}]`.

Common situations: Hand-written FK expressions copied from DDL without names; dbt-codegen or migration tooling emitting expression-only constraints; older dbt versions that did not require `name` on constraints.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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