dbt-labs/dbt-core · error · minijinja::Error::InvalidOperation

parse_constraints: {e}

Error message

parse_constraints: {e}

What it means

This error is raised by `typed_constraint::parse_constraints` when a contract-enforced model's column refs and model constraints cannot be parsed into not-null lists and typed constraints. The library wraps the failure as a minijinja InvalidOperation with the message 'parse_constraints: {e}'. It indicates the constraints declared on a contracted model are invalid for the columns they reference.

Source

Thrown at crates/dbt-adapter/src/adapter/adapter_impl.rs:4691

            })?;

        let model_constraints_vec: Vec<ModelConstraint> =
            minijinja_value_to_typed_struct(model_constraints.clone()).map_err(|e| {
                minijinja::Error::new(
                    minijinja::ErrorKind::SerdeDeserializeError,
                    format!("model_constraints: {e}"),
                )
            })?;

        let column_refs: Vec<DbtColumnRef> = model_columns_map
            .values()
            .map(|c| Arc::new(c.clone()))
            .collect();

        let (not_nulls, typed_constraints) = if contract_enforced {
            typed_constraint::parse_constraints(&column_refs, &model_constraints_vec).map_err(
                |e| {
                    minijinja::Error::new(
                        minijinja::ErrorKind::InvalidOperation,
                        format!("parse_constraints: {e}"),
                    )
                },
            )?
        } else {
            if model_columns_map
                .values()
                .any(|column| !column.constraints.is_empty())
            {
                let model_ref = if model_name.is_empty() {
                    String::new()
                } else {
                    format!(" on '{model_name}'")
                };
                emit_info_log_message(format!(
                    "Skipping column-level constraints{model_ref}: set `contract.enforced: true` \
                     to apply NOT NULL / primary key / foreign key / check constraints."

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Read the inner error text after 'parse_constraints: ' to find the offending constraint/column
  2. Verify every constraint's column matches a column defined in the model's `columns:` block
  3. Remove or fix constraints whose type is invalid for the column's data_type (contract validation is strict)
  4. Disable contract enforcement (`contract.enforced: false`) if contracts are not actually needed while debugging

Example fix

// before
columns:
  - name: user_id
    constraints:
      - type: foreign_key
// after
columns:
  - name: user_id
    constraints:
      - type: foreign_key
        expression: other_table (id)
Defensive patterns

Strategy: validation

Validate before calling

// before materializing a contracted model
let constraint_columns: HashSet<&str> = model_constraints.iter().filter_map(|c| c.columns.as_ref()).flatten().map(|s| s.as_str()).collect();
let defined: HashSet<&str> = column_refs.iter().map(|c| c.name.as_str()).collect();
let dangling: Vec<_> = constraint_columns.difference(&defined).collect();
if !dangling.is_empty() { return Err(format!("constraints reference unknown columns: {dangling:?}")); }

Type guard

fn constraint_columns_exist(constraints: &[ModelConstraint], cols: &[DbtColumnRef]) -> bool {
    let names: HashSet<&str> = cols.iter().map(|c| c.name()).collect();
    constraints.iter().all(|c| c.referenced_columns().iter().all(|col| names.contains(col.as_str())))
}

Try / catch

match typed_constraint::parse_constraints(&column_refs, &model_constraints_vec) {
    Ok(r) => r,
    Err(e) => return Err(minijinja::Error::new(minijinja::ErrorKind::InvalidOperation,
        format!("parse_constraints: {e}; check constraint column references and contract config"))),
}

Prevention

When it happens

Trigger: Materializing a model with `contract: {enforced: true}` where `parse_constraints(&column_refs, &model_constraints_vec)` fails — e.g. a constraint references a column name not present in column_refs, or a constraint type is incompatible with the declared column data type.

Common situations: Developers hit this when adding model contracts: a constraint names a column that was renamed or removed, a `check` constraint lacks an expression, or a foreign_key constraint references a missing column, all while contract enforcement is on.

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/041daf6462be4214. Report an issue: GitHub.