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
- Inspect the `{{ config(...) }}` calls in the failing model and ensure every value is a YAML-representable primitive, list, or string-keyed dict
- Convert non-string keys to strings before passing objects into config()
- Use `log()`/`print` in the model to dump the offending config argument and find the non-serializable value
- 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
- Only pass strings, numbers, booleans, lists and string-keyed dicts to {{ config() }}
- Never pass functions or minijinja objects into config()
- Test macros that build config dicts return plain serializable dicts
- Log the offending config payload when serialization fails
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
- Failed to serialize object
- Failed to convert value to YAML: {err}
- Invalid config object specified
- Invalid config object specified. Keys must be strings
- Version '{:?}' does not meet the required format
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/9c2734b98bdb3463.
Report an issue: GitHub.