dbt-labs/dbt-core · error · minijinja::Error (InvalidOperation)
Compilation Error for {} from {}: {}
Error message
Compilation Error for {} from {}: {} What it means
A model declares an enforced contract (contract.enforced: true) whose YAML column name/data_type/count does not match the columns the model's SQL actually produces. dbt renders a column-level diff and fails compilation for that node, attaching the node id and file path when available.
Source
Thrown at crates/dbt-jinja-utils/src/functions/base.rs:1216
// [{"name": ..., "data_type": ..., "formatted": ...},...]
"raise_contract_error" => {
let mut args = ArgParser::new(args, None);
let yaml_columns = args
.get::<Value>("yaml_columns")
.unwrap_or(Value::UNDEFINED);
let sql_columns = args.get::<Value>("sql_columns").unwrap_or(Value::UNDEFINED);
let column_diff_table: &Arc<AgateTable> =
get_contract_mismatches(yaml_columns, sql_columns)?;
let column_diff_display = column_diff_table
.display()
.with_max_rows(50)
.with_max_columns(50)
.with_max_column_width(50);
let message = format_args!(
"This model has an enforced contract that failed.\n Please ensure the name, data_type, and number of columns in your contract match the columns in your model's definition.\n\n{column_diff_display}"
);
if let Some((node_id, file_path)) = node_metadata_from_state(state) {
Err(Error::new(
ErrorKind::InvalidOperation,
format!(
"Compilation Error for {} from {}: {}",
node_id,
file_path.display(),
message
),
))
} else {
Err(Error::new(
ErrorKind::InvalidOperation,
format!("Compilation Error: {message}"),
))
}
}
// (column_names)
// ["column1", "column2"]
"column_type_missing" => {View on GitHub (pinned to 0267ce9170)
Solutions
- Align the YAML `columns:` block (names, data_type, count) with the model's actual SELECT output.
- If the change is intentional, update the contract in the YAML to the new schema.
- Temporarily set `contract.enforced: false` while iterating, then re-enable and fix.
- Read the rendered column diff in the error to see exactly which columns mismatch.
Example fix
# before (models/my_model.yml)
columns:
- name: id
data_type: int64
# model returns id BIGINT, user_name TEXT
# after
columns:
- name: id
data_type: bigint
- name: user_name
data_type: text Defensive patterns
Strategy: validation
Validate before calling
# Validate the contract YAML against the model's SELECT before running dbt
import yaml
spec = yaml.safe_load(open('models/my_model.yml'))
yaml_cols = [(c['name'], c['data_type']) for c in spec['models'][0]['columns']]
actual_cols = [(r[0], r[1]) for r in cursor.description] # from a test run of the model SQL
assert len(yaml_cols) == len(actual_cols), 'column count mismatch'
assert [n for n, _ in yaml_cols] == [n for n, _ in actual_cols], 'column names mismatch' Try / catch
// In the runner
if let Err(e) = dbt_build(&["--select", "my_model"]) {
if e.message.contains("enforced contract that failed") {
// print the column diff and halt the pipeline before downstream nodes
return Err(e);
}
return Err(e);
} Prevention
- Update the YAML columns block in the same PR as any model SQL column change.
- Keep data_type in YAML exactly matching warehouse types (watch varchar widths, int sizes).
- Run `dbt compile` + a dry query of the model SQL in CI to diff columns before merge.
- Only enable contract.enforced on stable models initially.
When it happens
Trigger: Running or building a contracted model where the SQL query returns columns that differ in name, data_type, or number from the columns listed in the model's YAML `columns:` block (diff is capped at 50 columns/50-char width for display).
Common situations: Adding a column to the SQL but forgetting the YAML contract; renaming a column; changing a data type (e.g. varchar width, int to bigint) in the model; dbt version upgrades that tighten type checking.
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
- Contract Error for {} from {}: {}
- Contract Error: {message}
- Column 'name' must be a string
- Expected a list of column definitions
- describe_dynamic_table is not supported by the {} adapter
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/b16acdca8c1f2375.
Report an issue: GitHub.