dbt-labs/dbt-core · error

Failed to serialize merged node config to dbt_yaml::Value fo

Error message

Failed to serialize merged node config to dbt_yaml::Value for parse model.config

What it means

When building the parse-time model context, the merged node config is serialized to a `dbt_yaml::Value` with `dbt_yaml::to_value` and the result is unwrapped with `expect`. Serialization of the merged config can only fail if the config contains values that cannot be represented in YAML (non-string map keys, unsupported types injected via `model.config(...)` jinja calls). The panic aborts parsing of that model.

Source

Thrown at crates/dbt-jinja-utils/src/phases/parse/resolve_model_context.rs:283

            compiled_code: None,
        },
        __adapter_attr__: AdapterAttr::default(),
        __other__: BTreeMap::new(),
        deprecated_config: ModelConfig::default(),
    };

    let mut model_map = convert_yml_to_value_map(InternalDbtNode::serialize(&model));
    // Stub `DbtModel` uses `ModelConfig::default()` for `config` in YAML serialization. At parse
    // time, kwargs to `config(...)` (e.g. `post_hook=my_macro(model)`) are evaluated while
    // rendering; macros must see the merged node config (`properties_config` / `BaseConfig`),
    // matching dbt-core (dbt-fusion#1414).
    //
    // Use `dbt_yaml::to_value` + `yml_value_to_minijinja` — same pipeline as
    // `DbtModel::serialized_config()` — not `MinijinjaValue::from_serialize`, so later
    // `dbt_yaml::to_value(model)` → `InternalDbtNodeWrapper::deserialize` in adapter helpers
    // (`get_view_options`, `get_config_from_model`, …) round-trips correctly.
    let config_yml = dbt_yaml::to_value(config)
        .expect("Failed to serialize merged node config to dbt_yaml::Value for parse model.config");
    model_map.insert("config".to_owned(), yml_value_to_minijinja(config_yml));
    model_map.insert(
        "batch".to_owned(),
        MinijinjaValue::from_object(init_batch_context()),
    );

    let result_store = ResultStore::default();
    let mut packages: BTreeSet<String> = runtime_config.dependencies.keys().cloned().collect();
    packages.insert(root_project_name.to_string());

    // Object-typed slots are wrapped via `MinijinjaValue::from_object(...)` /
    // `MinijinjaValue::from_function(closure)` HERE rather than in the typed
    // ctx struct, because going through serde's `serialize_map` /
    // `serialize_seq` paths can change the underlying Object's concrete type.
    // `builtins` must keep its BTreeMap shape for downstream downcasts, while
    // `model` is intentionally mutable to match dbt Core's dict behavior.
    let ctx = ResolveModelCtx {
        this: this_value,

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Inspect the `{{ config(...) }}` calls in the failing model and ensure every value is a YAML-representable primitive, list, or string-keyed dict
  2. Convert non-string keys to strings before passing objects into config()
  3. Use `log()`/`print` in the model to dump the offending config argument and find the non-serializable value
  4. At the code level, replace `expect` with an error carrying the serde message and the offending key/type

Example fix

// before (model.sql)
{{ config(materialized=table, tags={1: 'x'}) }}
// after
{{ config(materialized='table', tags={'1': 'x'}) }}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate config values are YAML-serializable before calling dbt_yaml::to_value
fn config_is_serializable<T: serde::Serialize>(config: &T) -> bool {
    dbt_yaml::to_value(config).is_ok()
}

Try / catch

let config_yml = dbt_yaml::to_value(config).map_err(|e|
    anyhow!("Failed to serialize merged node config for parse model.config: {e}"))?;

Prevention

When it happens

Trigger: Calling `{{ config(...) }}` in a model with a value dbt_yaml cannot serialize — e.g. `{{ config(my_dict_with_int_keys) }}`, passing a minijinja object/function as a config value, or a merged config containing non-YAML-serializable types.

Common situations: Users passing dicts with mixed/numeric keys to config(); macros returning exotic objects into config(); jinja-set config values that are functions or custom objects rather than primitives/lists/dicts.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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