dbt-labs/dbt-core · error · minijinja::Error::SerdeDeserializeError
get_common_options: Failed to deserialize InternalDbtNodeWra
Error message
get_common_options: Failed to deserialize InternalDbtNodeWrapper: {e} What it means
Raised by get_common_options() when the `node` argument fails to deserialize into InternalDbtNodeWrapper. The macro needs node metadata (relation info, config, resource type) to compute common options, so a non-conforming node value aborts with this SerdeDeserializeError and the serde reason appended.
Source
Thrown at crates/dbt-adapter/src/adapter/mod.rs:2195
let config_val = iter.next_arg::<&Value>()?;
let node_val = iter.next_arg::<&Value>()?;
let temporary = iter
.next_kwarg::<Option<bool>>("temporary")?
.unwrap_or(false);
iter.finish()?;
let config = minijinja_value_to_typed_struct::<ModelConfig>(config_val.clone())
.map_err(|e| {
minijinja::Error::new(
minijinja::ErrorKind::SerdeDeserializeError,
format!("get_common_options: Failed to deserialize config: {e}"),
)
})?;
let node = minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(
node_val.clone(),
)
.map_err(|e| {
minijinja::Error::new(
minijinja::ErrorKind::SerdeDeserializeError,
format!(
"get_common_options: Failed to deserialize InternalDbtNodeWrapper: {e}"
),
)
})?;
let options = adapter.get_common_options(state, config, &node, temporary)?;
Ok(options)
}
Parse(_) => Ok(none_value()),
}
}
/// Add time ingestion partition column
///
/// https://github.com/dbt-labs/dbt-adapters/blob/main/dbt-bigquery/src/dbt/adapters/bigquery/impl.py#L259
///View on GitHub (pinned to 0267ce9170)
Solutions
- Inspect the appended serde error for the missing or mistyped node field.
- Pass the real node object (e.g. `model` in a materialization) as the second argument.
- If building nodes programmatically, serialize a full InternalDbtNodeWrapper rather than a partial dict.
- Update templates and adapter together to avoid schema drift.
Example fix
// before
{% set opts = adapter.get_common_options(config.model, none) %}
// after
{% set opts = adapter.get_common_options(config.model, model) %} Defensive patterns
Strategy: validation
Validate before calling
{% if model is mapping and model.get('unique_id') is defined %}
{% set opts = adapter.get_common_options(config.model, model) %}
{% endif %} Type guard
fn is_node(val: &minijinja::Value) -> bool {
minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(val.clone()).is_ok()
} Prevention
- Always pass the real node object as the second argument
- Never pass None/undefined as node
- Serialize complete node objects in programmatic use
- Align template and adapter crate versions
When it happens
Trigger: adapter.get_common_options(config, node, temporary=...) invoked with node = None, a scalar, a relation object, or a dict missing required InternalDbtNodeWrapper fields (e.g. after schema changes or hand-crafted test nodes).
Common situations: Custom incremental/table materializations passing the wrong context variable for node; partial node dicts in tests; version mismatch between templates and adapter crate.
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
- get_table_options: Failed to deserialize InternalDbtNodeWrap
- get_view_options: Failed to deserialize InternalDbtNodeWrapp
- {}
- compute_external_path: Failed to deserialize config: {e}
- compute_external_path: Failed to deserialize InternalDbtNode
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/0c7391f4db3a5816.
Report an issue: GitHub.