dbt-labs/dbt-core · error · minijinja::Error::SerdeDeserializeError
model_constraints: {e}
Error message
model_constraints: {e} What it means
This error is raised when converting the `model_constraints` Minijinja Value into a typed `Vec<ModelConstraint>` struct via `minijinja_value_to_typed_struct` fails during model materialization in dbt-adapter. The library throws it because the constraints value passed from the Jinja/manifest layer did not deserialize into the expected ModelConstraint shape, meaning the model's constraint definitions are malformed or of an unexpected type. It surfaces as a SerdeDeserializeError wrapping the underlying serde message.
Source
Thrown at crates/dbt-adapter/src/adapter/adapter_impl.rs:4677
minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
"existing_columns must contain Column objects",
)
})
})
.collect::<Result<Vec<_>, _>>()?;
let model_columns_map: BTreeMap<String, DbtColumn> =
minijinja_value_to_typed_struct(model_columns.clone()).map_err(|e| {
minijinja::Error::new(
minijinja::ErrorKind::SerdeDeserializeError,
format!("model_columns: {e}"),
)
})?;
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}"),
)
},View on GitHub (pinned to 0267ce9170)
Solutions
- Check the model's YAML `constraints` definitions: each must be a mapping with a valid `type` key (not_null, unique, primary_key, foreign_key, check, etc.)
- Inspect the underlying serde message appended after 'model_constraints: ' to identify the exact field that failed to deserialize
- Ensure the caller producing `model_constraints` (manifest node or custom materialization) passes a list of constraint structs, not strings or dicts of another shape
- Align dbt-core and adapter versions so the ModelConstraint schema matches what the manifest emits
Example fix
// before (model.yml)
constraints:
- not_null
// after
constraints:
- type: not_null
columns: [id] Defensive patterns
Strategy: validation
Validate before calling
// caller-side guard
if (!Array.isArray(model_constraints) || model_constraints.some(c => typeof c !== 'object' || c === null || !('type' in c))) {
throw new Error('model_constraints must be a list of constraint objects each with a `type` field');
} Type guard
fn is_model_constraints(v: &Value) -> bool {
v.clone().try_into_object().map(|o| o.len() >= 0).is_ok()
} Try / catch
match minijinja_value_to_typed_struct::<Vec<ModelConstraint>>(model_constraints.clone()) {
Ok(v) => v,
Err(e) => return Err(format!("model_constraints deserialization failed: {e} - verify constraint YAML shape")),
} Prevention
- Validate model YAML constraints against the dbt constraints schema before run
- Keep dbt-core and adapter versions aligned
- Log the serialized model_constraints value on failure for diagnosis
When it happens
Trigger: Calling the adapter's model materialization path (near adapter_impl.rs:4677) with a `model_constraints` value that is not a serializable list of constraint objects — e.g. a dict, a string, or constraints missing required fields like `type`.
Common situations: A model defines `constraints` in YAML with a wrong structure (e.g. constraint given as a plain string instead of a dict with `type:`), a custom materialization passes incompatible data into model_constraints, or a version mismatch between the manifest schema and the ModelConstraint struct.
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
- {e}
- model_columns: {e}
- get_table_options: Failed to deserialize config: {e}
- get_seed_file_path: Failed to deserialize DbtSeed: {e}
- Failed to deserialize InternalDbtNodeWrapper: {e}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/0c496620fda46fb2.
Report an issue: GitHub.