BoundaryML/baml · error

Expected a statically defined string, not expression

Error message

Expected a statically defined string, not expression

What it means

as_static_str only returns values that are literal strings (or numerics) written directly in BAML source. A Jinja expression (e.g. "{{ something }}") needs evaluation at runtime, so the static accessor rejects it. The library throws this because a static string is required where the value is used (e.g. names, enum tags, provider fields) and an expression cannot be known at parse time.

Solutions

  1. Replace the Jinja expression with a static quoted string literal in the .baml file
  2. Move the dynamic interpolation to a place where it is allowed (e.g. prompt bodies, not static identifiers)
  3. In consuming Rust code, use resolve_string(&ctx) (with a context that can render the expression) instead of as_static_str()

Example fix

// before (baml)
enum Sentiment {
  "{{ Positive }}"
}
// after (baml)
enum Sentiment {
  Positive
}
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if matches!(v, UnresolvedValue::String(StringOr::JinjaExpression(_), _)) {
    anyhow::bail!("Jinja expressions are not allowed in this static field");
}
let s = v.as_static_str()?;

Type guard

fn is_static_string<Meta>(v: &UnresolvedValue<Meta>) -> bool {
    matches!(v, UnresolvedValue::String(StringOr::Value(_), _))
}

Prevention

When it happens

Trigger: Calling as_static_str() on UnresolvedValue::String(StringOr::JinjaExpression(..)) — a BAML field whose value is a Jinja template expression like {{ ctx.field }} or {{ _.name }} instead of a quoted literal.

Common situations: Developers interpolate dynamic values into BAML fields that must be static (client names, enum variant values, metadata strings), or copy template-style config between fields, then a static validation/registration pass fails.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

impl Default for EvaluationContext<'_> {
    fn default() -> Self {
        Self {
            env_vars: None,
            fill_missing_env_vars: true,
        }
    }
}

impl<Meta> UnresolvedValue<Meta> {
    pub fn as_static_str(&self) -> Result<&str> {
        match self {
            Self::String(StringOr::Value(v), ..) => Ok(v.as_str()),
            Self::String(StringOr::EnvVar(..), ..) => {
                anyhow::bail!("Expected a statically defined string, not env variable")
            }
            Self::String(StringOr::JinjaExpression(..), ..) => {
                anyhow::bail!("Expected a statically defined string, not expression")
            }
            Self::String(StringOr::TemplateStringCall { .. }, ..) => {
                anyhow::bail!("Expected a statically defined string, not a template_string call")
            }
            Self::Numeric(num, ..) => Ok(num.as_str()),
            Self::Array(..) => anyhow::bail!("Expected a string, not an array"),
            Self::Bool(..) => anyhow::bail!("Expected a string, not a bool"),
            Self::Map(..) => anyhow::bail!("Expected a string, not a map"),
            Self::Null(..) => anyhow::bail!("Expected a string, not null"),
            Self::ClassConstructor(..) => {
                anyhow::bail!("Expected a string, not a class constructor")
            }
        }
    }

    pub fn resolve_string(&self, ctx: &impl GetEnvVar) -> Result<String> {
        match self.resolve(ctx) {
            Ok(ResolvedValue::String(s, ..)) => Ok(s),

View on GitHub (pinned to bd85ce9dee)