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
- Fix the YAML syntax per the serde error in the message (check indentation/tabs around the reported line)
- Validate the YAML with a linter (yamllint) before saving
- Confirm field names and types match the DbtDescriptor schema (only known descriptor fields are allowed)
- 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
- Use spaces, never tabs, in descriptor YAML
- Lint YAML (yamllint) before saving
- Keep descriptor fields to the documented DbtDescriptor schema
- Avoid `{{{{ reserved }}}}` placeholders colliding with run argument names
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Document must be a string
- Unsupported trigger kind: ${target.triggerKind}
- the document must be a mapping (key: value)
- missing 'value' - paste a whole OpenFlow document, not just
- 'value.modules' must be a list
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/1d30cc90303e69ee.
Report an issue: GitHub.