BoundaryML/baml · error · anyhow::Error

Failed to parse template '{}': {}

Error message

Failed to parse template '{}': {}

What it means

`render_template` assembles all template_strings as minijinja macros plus the target template, then registers the combined source with `env.add_template`. If minijinja's parser rejects the source (syntax error, bad expression, unknown construct), the failure is wrapped as 'Failed to parse template <name>: <minijinja error>'.

Source

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

                    .map(|i| i.name.as_str())
                    .collect::<Vec<_>>()
                    .join(", ");
                format!(
                    "{{% macro {name}({args}) %}}{template}{{% endmacro %}}",
                    name = t.name(),
                    args = args_str,
                    template = t.template(),
                )
            })
            .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;

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Fix the Jinja syntax reported by the wrapped minijinja error (it follows the template name in the message)
  2. Check the template_string body in .baml for unbalanced blocks/braces and unsupported tags
  3. Only use filters available in the shared env (e.g. regex_match, sum) or register custom ones
  4. Render a minimal version of the template to isolate which line/expression fails to parse

Example fix

// before (.baml)
template_string T(x: string) #"{{ x | nonexistent_filter }}"#

// after (.baml)
template_string T(x: string) #"{{ x | upper }}"#
Defensive patterns

Strategy: try-catch

Validate before calling

// Basic pre-check before rendering
function looksLikeBalancedJinja(src: string): boolean {
  const open = (src.match(/{%/g) || []).length, close = (src.match(/%}/g) || []).length;
  const openE = (src.match(/{{/g) || []).length, closeE = (src.match(/}}/g) || []).length;
  return open === close && openE === closeE;
}

Try / catch

try {
  const rendered = render_template(name, args);
} catch (e) {
  if (String(e).startsWith('Failed to parse template')) {
    console.error('Invalid Jinja in template_string; check blocks/filters:', e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Rendering a BAML template_string whose body contains invalid Jinja syntax — unbalanced {% %}, unknown filters/tags not registered in get_env(), malformed {{ expr }} — encountered during test argument evaluation.

Common situations: Copy-pasting Jinja2 features minijinja doesn't support; typos in expressions or filter names; an edit to one template_string breaking the concatenated macro source; version differences in minijinja filter availability (regex_match/sum).

Understand the failure class

Related errors


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