BoundaryML/baml · error
Expected a statically defined string, not env variable
Error message
Expected a statically defined string, not env variable
What it means
BAML's UnresolvedValue::as_static_str extracts a literal string from a statically-parsed BAML value (e.g. a model provider option, client name, or metadata field). It refuses to read an env-var reference (env::VAR or $VAR) because doing so requires runtime resolution with an environment context, which this zero-cost static accessor deliberately does not perform. The library throws this to force callers to either use resolve_string(ctx) or provide a literal.
Source
Thrown at engine/baml-lib/baml-types/src/value_expr.rs:519
}
}
}
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")
}
}
}
View on GitHub (pinned to bd85ce9dee)
Solutions
- Replace the env-var reference with a static string literal in the .baml file if the value never varies between environments
- Call resolve_string(ctx) with an EvaluationContext holding the env vars instead of as_static_str() in the consuming code
- Ensure the env var is set and passed into the BAML runtime (EvaluationContext::new(&env_map, ...)) so resolution happens at runtime, not static parse time
Example fix
// before (baml)
client MyClient {
provider openai
options {
api_key env.OPENAI_API_KEY
}
}
// after (baml)
client MyClient {
provider openai
options {
api_key "sk-static-or-injected-key"
}
}
// or in Rust, resolve at runtime instead:
// let s = value.resolve_string(&ctx)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust
fn needs_static(v: &UnresolvedValue<()>) -> Result<&str> {
if let UnresolvedValue::String(StringOr::EnvVar(_), _) = v {
anyhow::bail!("field must be a static string, not env::VAR");
}
v.as_static_str()
} Type guard
fn is_static_string<Meta>(v: &UnresolvedValue<Meta>) -> bool {
matches!(v, UnresolvedValue::String(StringOr::Value(_), _))
} Prevention
- Keep env-var references out of fields consumed by static/compile-time passes
- Pass a populated env map into EvaluationContext and prefer resolve_string for runtime paths
- Document which BAML fields must be literals
When it happens
Trigger: Calling as_static_str() on an UnresolvedValue::String(StringOr::EnvVar(..)) — i.e. the BAML source declares the field as an environment-variable reference like BAML_ENV_VAR or "env.MY_KEY" instead of a plain quoted string.
Common situations: Developers parameterize BAML config (model name, API key field, client id) via env vars for dev/prod portability, then a compile-time/static pass (LLM client registration, client schema validation, or tooling that reads baml_src without env vars) tries to read the value statically and fails.
Related errors
- Expected a statically defined string, not expression
- Expected a statically defined string, not a template_string
- Expected a string, not an array
- Expected a string, not a bool
- Expected a string, not a map
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/626e1a959a7cfcb9.
Report an issue: GitHub.