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
- Fix the Jinja syntax reported by the wrapped minijinja error (it follows the template name in the message)
- Check the template_string body in .baml for unbalanced blocks/braces and unsupported tags
- Only use filters available in the shared env (e.g. regex_match, sum) or register custom ones
- 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
- Keep template_string bodies to minijinja-supported syntax and filters
- Check block/tag balance after editing templates
- Render templates in CI tests to catch parse errors early
- Avoid Jinja2-only features and unregistered custom filters
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- {0}
- Template string '{}' expects {} arguments, but {} were provi
- Failed to get template '{}': {}
- Expected a statically defined string, not expression
- interned member `{name}` cannot be another member's child
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/08b8750d56042a31.
Report an issue: GitHub.