dbt-labs/dbt-core · warning

In relation : The following columns are specified in the…

Error message

In relation {relation.render()}: The following columns are specified in the schema but are not present in the database: {missing | join(", ")}

What it means

During persist_docs, dbt compares the columns declared in the model's schema (YAML/docs config) against the columns actually present in the materialized relation. Columns declared in the schema but missing from the database are collected into `missing` and reported via this warning so users know their docs/config reference columns that don't exist.

Solutions

  1. Update the model's YAML docs/columns block so it only lists columns that exist in the built relation.
  2. Rebuild/run the model so the relation matches the declared schema, then re-run `dbt docs generate` or persist_docs.
  3. Check for case-sensitivity or quoting mismatches between the schema column names and the database column names.

Example fix

// before (schema.yml)
columns:
  - name: old_col
// after
columns:
  - name: new_col
Defensive patterns

Strategy: validation

Validate before calling

# Compare declared docs columns against the relation before persisting docs
# dbt: run `dbt compile && dbt run-operation get_columns_specified_in --args ...`
# or in Python after a run:
# relation_columns = {c.name for c in adapter.get_columns(relation)}
# yaml_columns = set(model['columns'].keys())
# assert yaml_columns <= relation_columns, f"missing: {yaml_columns - relation_columns}"

Prevention

When it happens

Trigger: Calling default__persist_docs (or get_columns_specified_in but not in the database) where iterating the model's column specs finds a name that has no entry in the database relation's column list, appending it to `missing`.

Common situations: YAML docs blocks list a column that was renamed or dropped in the model SQL; case-sensitivity mismatch between the schema file and the database; persist_docs enabled on an external/view relation whose columns drifted from the declared schema.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at crates/dbt-loader/src/dbt_macro_assets/dbt-adapters/macros/adapters/persist_docs.sql:51

{% macro validate_doc_columns(relation, column_dict, existing_column_names, case_insensitive=false) %}
  {% set existing_lower = existing_column_names | map("lower") | list %}
  {% set missing = [] %}
  {% set filtered = {} %}
  {% for col_name in column_dict %}
    {% set is_quoted = column_dict[col_name]['quote'] %}
    {% if case_insensitive or not is_quoted %}
      {% set present = col_name | lower in existing_lower %}
    {% else %}
      {% set present = col_name in existing_column_names %}
    {% endif %}
    {% if present %}
      {% do filtered.update({col_name: column_dict[col_name]}) %}
    {% else %}
      {% do missing.append(col_name) %}
    {% endif %}
  {% endfor %}
  {% if missing | length > 0 %}
    {{ exceptions.warn("In relation " ~ relation.render() ~ ": The following columns are specified in the schema but are not present in the database: " ~ missing | join(", ")) }}
  {% endif %}
  {{ return(filtered) }}
{% endmacro %}

-- funcsign: (relation, model, optional[bool], optional[bool]) -> string
{% macro default__persist_docs(relation, model, for_relation, for_columns) -%}
  {% if for_relation and config.persist_relation_docs() and model.description %}
    {% do run_query(alter_relation_comment(relation, model.description)) %}
  {% endif %}

  {% if for_columns and config.persist_column_docs() and model.columns %}
    {% set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list %}
    {% set filtered_columns = validate_doc_columns(relation, model.columns, existing_columns) %}
    {% set alter_comment_sql = alter_column_comment(relation, filtered_columns) %}
    {% if alter_comment_sql and alter_comment_sql | trim | length > 0 %}
      {% do run_query(alter_comment_sql) %}
    {% endif %}
  {% endif %}

View on GitHub (pinned to 0267ce9170)