BoundaryML/baml · error

Expected a statically defined string, not a template_string

Error message

Expected a statically defined string, not a template_string call

What it means

as_static_str cannot return a value for a template_string(...) call, because the rendered text only exists after runtime evaluation with arguments and a render context. The library throws this whenever a static string accessor encounters a TemplateStringCall variant, forcing the caller to resolve the value at runtime instead.

Source

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

        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),
            _ => Err(anyhow::anyhow!("Expected a string")),
        }
    }

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Inline the rendered text as a static string literal if it is fully known at authoring time
  2. Use resolve_string(&ctx) with an EvaluationContext whose render_template implementation can render the template
  3. Restructure the BAML config so template_string calls are only used in runtime-evaluated positions (prompts), not static fields

Example fix

// before (baml)
options {
  model template_string("gpt-{0}", ["4o"])
}
// after (baml)
options {
  model "gpt-4o"
}
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if matches!(v, UnresolvedValue::String(StringOr::TemplateStringCall { .. }, _)) {
    anyhow::bail!("template_string calls cannot be used in static fields");
}
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::TemplateStringCall{..}) — a BAML field whose value is a template_string("...", args) call expression rather than a literal.

Common situations: Developers build strings in BAML with template_string() for reuse (e.g. composing a model name or a header value), then a compile-time step that requires literal values (client registration, enum/tag validation) rejects it.

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/b266f7d0b7021df1. Report an issue: GitHub.