dbt-labs/dbt-core · warning
contract.enforced=true on materialized_view
Error message
contract.enforced=true on materialized_view '{{ model.name }}': not supported by dbt (https://docs.getdbt.com/docs/mesh/govern/model-contracts). dbt-databricks provides best-effort support that may change without notice. What it means
dbt core does not support model contracts on materialized views. When a dbt-databricks materialized view has `contract.enforced: true`, the adapter warns that its contract support is best-effort and may change, then still reads model constraints/columns to build the view. It is a heads-up that contract behavior here is non-standard and unprotected by core guarantees.
Solutions
- Remove `contract.enforced` (or set it false) for materialized_view models
- Scope the contract config to supported materializations only (tables/views) via `config` selectors or per-model YAML
- If you rely on it, pin dbt-databricks versions and re-validate MV contract behavior on upgrades
Example fix
# before
models:
- name: my_mv
config:
materialized: materialized_view
contract:
enforced: true
# after
models:
- name: my_mv
config:
materialized: materialized_view
# keep contracts on table models only Defensive patterns
Strategy: validation
Validate before calling
def check_contract_on_mv(model):
if model.get('config', {}).get('materialized') == 'materialized_view':
assert not model.get('config', {}).get('contract', {}).get('enforced'), \
f"{model['name']}: contract.enforced not supported on materialized_view" Prevention
- Scope contract configs to table/view materializations only
- Avoid blanket `+contract:` config inheritance onto materialized views
- Review the dbt core contract support matrix per materialization
- Treat the warning as a prompt to remove the config, not to ignore it
When it happens
Trigger: A materialized view model sets `config.contract.enforced=true` (via YAML config or `{{ config(...) }}`) and is built with dbt-databricks.
Common situations: Applying a shared `contract` config block across all models including MVs; adopting contracts for governance and applying them uniformly; copy-pasted model configs from table models.
Related errors
- Column 'name' must be a string
- Compilation Error for
- Configuration changes were identified and…
- Constraint of type } with no `name` provided. Generating…
- Contract Error for from
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/ac19e5207d90b692.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-loader/src/dbt_macro_assets/dbt-databricks/macros/relations/materialized_view/create.sql:32
{# DIVERGENCE END #}
{#
TODO: When DESCRIBE QUERY EXTENDED is supported, this implementation should be simplified
to use that instead. For now, we work around this limitation by writing results to a
temporary view and using DESCRIBE TABLE EXTENDED on the temporary view.
#}
{%- set temp_relation = make_temp_relation(relation) -%}
{% call statement('create_temp_view') -%}
{%- set sql_with_limit = sql.rstrip('; \n\t') ~ ' LIMIT 10' -%}
{{ create_temporary_view(temp_relation, sql_with_limit) }}
{%- endcall %}
{%- set columns = adapter.get_columns_in_relation(temp_relation) -%}
{%- set model_columns = model.get('columns', {}) -%}
{%- set contract_config = config.get('contract') -%}
{%- set contract_enforced = contract_config and contract_config.enforced -%}
{%- if contract_enforced -%}
{%- do exceptions.warn(
"contract.enforced=true on materialized_view '" ~ model.name ~ "': not supported by dbt (https://docs.getdbt.com/docs/mesh/govern/model-contracts). dbt-databricks provides best-effort support that may change without notice."
) -%}
{%- set model_constraints = model.get('constraints', []) -%}
{%- else -%}
{%- set model_constraints = [] -%}
{%- endif -%}
{%- set columns_and_constraints = adapter.parse_columns_and_constraints(columns, model_columns, model_constraints, contract_enforced, model.name) -%}
{%- set target_relation = relation.enrich(columns_and_constraints[1]) -%}
create or replace materialized view {{ target_relation.render() }}
{{ get_column_and_constraints_sql(target_relation, columns_and_constraints[0]) }}
{{ get_create_row_filter_clause(target_relation) }}
{{ get_create_sql_partition_by(partition_by) }}
{{ liquid_clustered_cols() }}
{{ get_create_sql_comment(comment) }}
{{ get_create_sql_tblproperties(tblproperties) }}
{{ get_create_sql_refresh_schedule(refresh.cron, refresh.time_zone_value) }}
asView on GitHub (pinned to 0267ce9170)