BoundaryML/baml · error · anyhow::Error

Failed to render template '{}': {}

Error message

Failed to render template '{}': {}

What it means

BAML renders Jinja templates for prompt parts via minijinja. When tmpl.render(context) fails, the minijinja error is wrapped in this message with the template name. It means the template syntax parsed fine but execution failed — e.g. an undefined variable, a bad filter, or a runtime type error during rendering.

Source

Thrown at engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs:2091

            })
            .chain(std::iter::once(template_content.to_string()))
            .collect::<Vec<_>>()
            .join("\n");

        // Use the shared environment (trim_blocks, lstrip_blocks, debug,
        // null formatter, regex_match/sum filters) to match the prompt renderer.
        let mut env = get_env();
        env.add_template("__template__", &full_template)
            .map_err(|e| anyhow::anyhow!("Failed to parse template '{}': {}", name, e))?;

        let tmpl = env
            .get_template("__template__")
            .map_err(|e| anyhow::anyhow!("Failed to get template '{}': {}", name, e))?;

        let context = minijinja::Value::from_serialize(&args_map);
        let rendered = tmpl
            .render(context)
            .map_err(|e| anyhow::anyhow!("Failed to render template '{}': {}", name, e))?;

        Ok(rendered)
    }
}

#[cfg(test)]
mod render_template_tests {
    use baml_types::TemplateStringRenderer;
    use repr::make_test_ir;

    use super::*;

    #[test]
    fn render_basic_template() {
        let ir = make_test_ir(
            r##"
            template_string Greet(name: string) #"
                Hello, {{ name }}!

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Read the inner minijinja error after ': {}' — it names the exact variable/filter that failed.
  2. Verify every {{ var }} in the template exists in the args passed to the function.
  3. Replace unsupported Jinja2 filters/syntax with minijinja-compatible equivalents.
  4. Print or log args_map before rendering to confirm keys match template references.

Example fix

// before
{{ user.nmae | upper }}
// after
{{ user.name | upper }}
Defensive patterns

Strategy: validation

Validate before calling

fn template_vars_ok(template: &str, args: &serde_json::Map<String, serde_json::Value>) -> bool {
    // crude check: every {{ var }} referenced has a matching arg key
    template.match_indices("{{").all(|(i, _)| {
        let rest = &template[i + 2..];
        let name: String = rest.chars().take_while(|c| !c.is_whitespace() && *c != '|' && *c != '}').collect();
        name.is_empty() || args.contains_key(&name)
    })
}

Try / catch

match render_template(&name, &args) {
    Ok(r) => r,
    Err(e) if e.to_string().contains("Failed to render template") => {
        eprintln!("render failed: {e:#}"); // inner error names the bad var/filter
        fallback_template()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Rendering a BAML prompt/partial template whose body references missing variables not present in args_map, applies an unknown filter, or performs an invalid operation (e.g. iterating a non-iterable) at render time.

Common situations: Typo in a variable name inside {{ }} blocks; using a Jinja filter not supported by minijinja; passing args whose shape doesn't match what the template expects; templates copied from Jinja2 docs using unsupported features.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/c47e617113be9fe6. Report an issue: GitHub.