dbt-labs/dbt-core · warning

InvalidConfig

InvalidConfig

Error message

Resource path `{key_path}` in dbt_project.yml starts with `+`. This will be deprecated in future versions of dbt.

What it means

A deprecation warning from the dbt project-file parser: a resource-path key under a config section (models, seeds, snapshots, etc.) in dbt_project.yml starts with '+', and the sub-tree carries actual config values (value.has_set_fields() is true). The '+' prefix convention for configs in dbt_project.yml is being deprecated, so warn_plus_prefixed_resource_paths emits one warning at the topmost '+'-prefixed key of each offending resource path (code InvalidConfig). Parsing continues; the config still applies today.

Source

Thrown at crates/dbt-parser/src/dbt_project_config.rs:482

    };

    // Case 1: `value` is non-default, meaning there is a valid config inside it somewhere.
    // We definitely know a config value was set, because it must have this shape:
    //
    // ```
    // +key:
    //   +some_config: some_value
    // ```
    //
    // This is just an approximation and will miss cases where the config is explicitly set to
    // default.
    let valid_config_exists = value.has_set_fields();

    // We want to throw warnings at the location of the topmost +-prefixed key, so we throw exactly
    // one warning per offending resource path.
    let is_parent_plus = key_is_plus && !inside_plus;
    if is_parent_plus && valid_config_exists {
        warn();
        return key_is_plus;
    }

    // Case 2: Any non-config children start with +, or any descendants fall under case 1.
    let mut any_child_plus = false;
    for (child_key, child_variant) in value.iter_children() {
        let child_is_plus = match child_variant {
            ShouldBe::AndIs(child) => warn_plus_prefixed_resource_paths::<S>(
                child_key,
                child,
                &key_path,
                inside_plus || key_is_plus,
            ),
            ShouldBe::ButIsnt(..) => child_key.starts_with('+'),
        };
        any_child_plus |= child_is_plus;
    }
    if is_parent_plus && any_child_plus {

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Remove the '+' prefix from resource-path keys in dbt_project.yml: use 'my_model: materialized: table' style nested configs
  2. Keep '+' prefixes only where still required (e.g. seed/test config keys under subdirectories if applicable) and audit each section of dbt_project.yml
  3. Run dbt parse/dbt debug and clear each reported path until no warnings remain

Example fix

# before (dbt_project.yml)
models:
  my_project:
    +materialized: table
# after
models:
  my_project:
    config:
      materialized: table
Defensive patterns

Strategy: validation

Validate before calling

import yaml
def find_plus_keys(node, path=""):
    if isinstance(node, dict):
        for k, v in node.items():
            p = f"{path}.{k}" if path else k
            if k.startswith('+'):
                print(f"Deprecated '+' prefix: {p}")
            find_plus_keys(v, p)

Prevention

When it happens

Trigger: dbt_project.yml contains e.g. 'models: { +my_model: { +materialized: table } }' or any '+'-prefixed resource key whose nested value sets at least one config field; triggered at the outermost plus key (inside_plus == false).

Common situations: Upgrading from dbt versions where '+key:' was the documented convention; mixed legacy/new configs after migration; linters or generators that still emit '+'-prefixed project configs.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


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