dbt-labs/dbt-core · error

Failed to deserialize InternalDbtNodeWrapper: {e}

Error message

Failed to deserialize InternalDbtNodeWrapper: {e}

What it means

This error is raised in `dynamic_table_config_changeset` when `minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>` fails to deserialize the relation's config value into an InternalDbtNodeWrapper. The library wraps deserialization failures with this message so Jinja-level callers get a SerdeDeserializeError instead of a panic. It means the config value passed from the model context does not match the expected internal node schema.

Source

Thrown at crates/dbt-adapter/src/relation/relation_impl.rs:1022

            (_, _) => false,
        }
    }

    // https://github.com/dbt-labs/dbt-adapters/blob/292d17301eff3c8a972fcd57f7deb3aac4c8a3cb/dbt-snowflake/src/dbt/adapters/snowflake/relation.py#L92
    fn dynamic_table_config_changeset(
        &self,
        relation_results_value: &Value,
        relation_config_value: &Value,
    ) -> Result<Value, minijinja::Error> {
        match self.adapter_type {
            AdapterType::Snowflake => {
                // TODO(serramatutu): minijinja_value_to_typed_struct does not work with references, so we
                // have to clone the value here...
                let local_config = minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(
                    relation_config_value.clone(),
                )
                .map_err(|e| {
                    minijinja::Error::new(
                        minijinja::ErrorKind::SerdeDeserializeError,
                        format!("Failed to deserialize InternalDbtNodeWrapper: {e}"),
                    )
                })?;
                let local_config = match local_config {
                    InternalDbtNodeWrapper::Model(model) => model,
                    _ => {
                        return Err(minijinja::Error::new(
                            minijinja::ErrorKind::InvalidOperation,
                            "Expected a model node",
                        ));
                    }
                };

                dynamic_table_config_changeset_from_local_config(
                    local_config.as_ref(),
                    relation_results_value,
                )

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Inspect the nested error text (`{e}`) to find which field failed to deserialize and fix the model config value accordingly.
  2. Verify you are passing the model's full config (node config) and not an unrelated object into dynamic_table_config_changeset.
  3. Ensure the adapter crate and dbt node schema versions match; upgrade or pin the adapter to your dbt version.
  4. Check that the config value is a Model node wrapper (InternalDbtNodeWrapper::Model) and not another node variant.

Example fix

// before
relations.dynamic_table_config_changeset(config.model_config_dict)
// after
relations.dynamic_table_config_changeset(config)
Defensive patterns

Strategy: try-catch

Validate before calling

// In Jinja, check config is a node config object before calling
if config is not mapping:
    raise Exception('config must be the model config object')

Type guard

fn is_model_wrapper(v: &Value) -> bool {
    minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(v.clone())
        .map(|w| matches!(w, InternalDbtNodeWrapper::Model(_)))
        .unwrap_or(false)
}

Try / catch

match minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(value) {
    Ok(w) => use(w),
    Err(e) => log_error_and_skip(format!("bad config: {e}")),
}

Prevention

When it happens

Trigger: Calling the relation's `dynamic_table_config_changeset` Jinja method with a `config` value that is not a valid serialized InternalDbtNode (e.g. a dict missing required fields, wrong field types, or a wrapper for a different node kind).

Common situations: Model configs with fields typed differently from the NodeConfig struct (e.g. strings where integers are expected), passing a raw relation config instead of the full node config, or schema drift between the adapter crate and the node definitions after a version upgrade.

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/231a25cb9b2d170c. Report an issue: GitHub.