windmill-labs/windmill · error

Failed to parse dbt descriptor: {e}

Error message

Failed to parse dbt descriptor: {e}

What it means

parse_dbt_descriptor deserializes a dbt descriptor YAML string into DbtDescriptor via serde_yml. Malformed YAML or fields that do not fit the descriptor schema raise this error wrapping serde's diagnostic; a second validation layer afterwards also rejects placeholders that collide with reserved run argument names.

Source

Thrown at backend/parsers/windmill-parser-yaml/src/dbt.rs:269

/// spreads over the run's arguments to read them — a placeholder of the same
/// name would be shadowed there, and the script could never be run (`select` is
/// an array, and interpolating one into a string is not something any invocation
/// can satisfy).
pub const RESERVED_ARG_NAMES: &[&str] = &[
    "command",
    "select",
    "exclude",
    "vars",
    "full_refresh",
    "dbt_command",
    "dbt_retry_job",
    "model",
    "limit",
];

pub fn parse_dbt_descriptor(inner_content: &str) -> anyhow::Result<DbtDescriptor> {
    let d = serde_yml::from_str::<DbtDescriptor>(inner_content)
        .map_err(|e| anyhow::anyhow!("Failed to parse dbt descriptor: {e}"))?;
    if let Some(name) = placeholders(&d)
        .into_iter()
        .find(|n| RESERVED_ARG_NAMES.contains(&n.as_str()))
    {
        return Err(anyhow::anyhow!(
            "`{{{{ {name} }}}}` collides with the run argument `{name}` this runtime already \
             defines ({}); rename the placeholder",
            RESERVED_ARG_NAMES.join(", ")
        ));
    }
    Ok(d)
}

/// The workspace warehouse a descriptor gets when it names none — spelled like
/// the default lake (`ducklake://main.orders`), so one workspace concept reads
/// the same across kinds.
pub const DBT_DEFAULT_WAREHOUSE: &str = "main";

View on GitHub (pinned to e474e8803c)

Solutions

  1. Fix the YAML syntax per the serde error in the message (check indentation/tabs around the reported line)
  2. Validate the YAML with a linter (yamllint) before saving
  3. Confirm field names and types match the DbtDescriptor schema (only known descriptor fields are allowed)
  4. Remove any `{{{{ reserved_name }}}}` placeholders if the follow-up validation fires

Example fix

# before (tab indentation)
descriptor:
	name: my_model
# after
descriptor:
  name: my_model
Defensive patterns

Strategy: validation

Validate before calling

// validate descriptor YAML before deploy (JS example)
const yaml = require('js-yaml');
try { yaml.load(descriptorYaml); } catch (e) { throw new Error('Invalid dbt descriptor YAML: ' + e.message); }

Type guard

function isValidDescriptorYaml(s) { try { return typeof yaml.load(s) === 'object'; } catch { return false; } }

Try / catch

try {
  parseDbtDescriptor(yamlStr);
} catch (e) {
  if (String(e).includes('Failed to parse dbt descriptor')) {
    // surface serde's message (it names the YAML line/problem)
  } else throw e;
}

Prevention

When it happens

Trigger: parse_dbt_sig / dbt_arg_schema called with inner_content that is not valid YAML (bad indentation, tabs, duplicate keys) or whose structure does not match DbtDescriptor's schema (wrong types, unexpected field shapes).

Common situations: Hand-edited dbt descriptor files in scripts, copy-pasted YAML with tabs instead of spaces, an editor converting indentation, or referencing a schema version whose fields changed.

Understand the failure class

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/1d30cc90303e69ee. Report an issue: GitHub.