dbt-labs/dbt-core · error

Invalid config object specified

Error message

Invalid config object specified

What it means

When processing a `{{ config(...) }}` call at parse time, a positional argument is expected to be an iterable object of key/value pairs; `try_iter_pairs()` is unwrapped with `expect('Invalid config object specified')`. The panic fires when the positional config argument is an object that cannot be iterated as pairs (e.g. a non-dict object, or a scalar that slipped past the earlier object check).

Source

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

    ) -> Result<MinijinjaValue, MinijinjaError> {
        let mut args = ArgParser::new(args, None);
        // If there is a positional argument, it must be a map
        let kwargs = if args.positional_len() == 1 {
            let positional_val: MinijinjaValue = args.next_positional::<MinijinjaValue>()?;
            if positional_val.kind() != ValueKind::Map {
                return Err(MinijinjaError::new(
                    MinijinjaErrorKind::InvalidOperation,
                    format!(
                        "Invalid config argument kind specified: {}",
                        positional_val.kind()
                    ),
                ));
            }
            positional_val
                .as_object()
                .unwrap()
                .try_iter_pairs()
                .expect("Invalid config object specified")
                .map(|(k, v)| {
                    (
                        k.as_str()
                            .expect("Invalid config object specified. Keys must be strings")
                            .to_string(),
                        v,
                    )
                })
                .collect()
        } else {
            args.drain_kwargs()
        };

        self.apply_config(state, kwargs)
    }

    fn call_method(
        self: &Arc<Self>,

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Ensure the positional argument to `{{ config(...) }}` is a plain dict with string keys, e.g. `{{ config(materialized='table') }}` or `{{ config({'materialized': 'table'}) }}`
  2. If a macro builds the config, have it return a normal dict (not a custom object)
  3. Log/print the value in the model to see its actual type before the config call
  4. At the code level, replace expect with an error message that includes the received value's type

Example fix

// before (model.sql)
{{ config(some_macro_that_returns_object()) }}
// after
{% set cfg = some_macro_that_returns_dict() %}
{{ config(cfg) }}
Defensive patterns

Strategy: validation

Validate before calling

{% set cfg = my_config_arg() %}
{% if cfg is not mapping %}
  {{ exceptions.raise_compiler_error("config() positional arg must be a dict, got: " ~ type(cfg)) }}
{% endif %}
{{ config(cfg) }}

Type guard

// in jinja: only pass mappings
{% if cfg is mapping %}{{ config(cfg) }}{% endif %}

Try / catch

// in Rust, replace expect with a descriptive error
obj.try_iter_pairs().ok_or_else(|| MinijinjaError::new(
    ErrorKind::InvalidOperation, "config() positional arg must be an iterable dict"))?;

Prevention

When it happens

Trigger: Calling `{{ config(some_object) }}` where the object is not a plain dict — e.g. a minijinja native object, a function, a struct-like value, or a nested/odd type returned by a macro that passes the `as_object()` check but not pair iteration.

Common situations: Macros returning custom objects into config(); passing a list or string positionally to config(); users passing `config(kwargs)` where kwargs was rebuilt into an unsupported type.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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