BoundaryML/baml · error

Jinja expressions cannot be resolved without a template cont

Error message

Jinja expressions cannot be resolved without a template context

What it means

ValueExpr::resolve handles only statically-known variants: EnvVar and Value. JinjaExpression needs a rendered template context to evaluate, so resolve explicitly rejects it with this error instead of silently producing a wrong string. The variant is not an error per se — the wrong resolution API was used.

Source

Thrown at engine/baml-lib/baml-types/src/value_expr.rs:305

    pub fn maybe_eq(&self, other: &StringOr) -> bool {
        match (self, other) {
            (Self::Value(s), Self::Value(o)) => s == o,
            (Self::Value(_), _) | (_, Self::Value(_)) => true,
            (Self::EnvVar(_), Self::JinjaExpression(_))
            | (Self::JinjaExpression(_), Self::EnvVar(_)) => true,
            (Self::JinjaExpression(_), Self::JinjaExpression(_)) => true,
            (Self::EnvVar(s), Self::EnvVar(o)) => s == o,
            // Template string calls could evaluate to anything, so conservatively return true
            (Self::TemplateStringCall { .. }, _) | (_, Self::TemplateStringCall { .. }) => true,
        }
    }

    pub fn resolve(&self, ctx: &impl GetEnvVar) -> Result<String> {
        match self {
            Self::EnvVar(name) => ctx.get_env_var(name),
            Self::Value(value) => Ok(value.to_string()),
            Self::JinjaExpression(_) => {
                anyhow::bail!("Jinja expressions cannot be resolved without a template context")
            }
            Self::TemplateStringCall { name, .. } => {
                anyhow::bail!(
                    "Template string call '{}' cannot be resolved without IR context. \
                     Use resolve_with_templates() instead.",
                    name
                )
            }
        }
    }

    /// Resolve this StringOr, with support for template_string calls.
    pub fn resolve_with_templates(
        &self,
        ctx: &impl GetEnvVar,
        template_renderer: &impl TemplateStringRenderer,
    ) -> Result<String> {
        match self {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Use resolve_with_templates() (or the full IR-aware resolver) which supplies a template context.
  2. Ensure a template renderer is available where the ValueExpr is resolved.
  3. If the value should be static, replace the Jinja expression in the configuration with a literal or env-var reference.

Example fix

// before
let v = expr.resolve(&env)?;
// after
let v = expr.resolve_with_templates(&env, &template_renderer)?;
Defensive patterns

Strategy: type-guard

Validate before calling

if matches!(expr, ValueExpr::JinjaExpression(_) | ValueExpr::TemplateStringCall { .. }) { return Err(anyhow!("needs template-aware resolver")); }

Type guard

fn is_statically_resolvable(e: &ValueExpr) -> bool { matches!(e, ValueExpr::EnvVar(_) | ValueExpr::Value(_)) }

Try / catch

let v = expr.resolve_with_templates(&env, &renderer).map_err(|e| anyhow!("resolution failed: {}", e))?;

Prevention

When it happens

Trigger: Calling resolve() on a ValueExpr that contains Self::JinjaExpression, e.g. resolving API key expressions or config values that embed {{ ... }} Jinja expressions without a template context.

Common situations: Resolving client/API-key configuration strings that users wrote with Jinja expressions (e.g. dynamic headers) via the simple env-var-only resolver.

Related errors


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