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

  1. Align the YAML `columns:` block (names, data_type, count) with the model's actual SELECT output.
  2. If the change is intentional, update the contract in the YAML to the new schema.
  3. Temporarily set `contract.enforced: false` while iterating, then re-enable and fix.
  4. 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

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


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