BoundaryML/baml · error
Expected a string, not a class constructor
Error message
Expected a string, not a class constructor
What it means
as_static_str rejects UnresolvedValue::ClassConstructor — a reference to a BAML class name used as a value (e.g. for polymorphic fields). A constructor reference is not a string value even though it is written like an identifier, so the accessor bails rather than returning the class name text.
Solutions
- Quote the value as a string literal if a plain string is intended, instead of referencing the class
- In consuming code, match the ClassConstructor variant explicitly and use its data (construct the class or read its name field) instead of as_static_str()
- Tighten the BAML schema so the field's type is string, making constructor references a validation error earlier
Example fix
// before (baml) field MyEnum // class/enum constructor reference // after (baml) field "MyEnum"
Defensive patterns
Strategy: type-guard
Validate before calling
// Rust
if matches!(v, UnresolvedValue::ClassConstructor(..)) {
anyhow::bail!("constructor reference found where a string is required");
}
let s = v.as_static_str()?; Type guard
fn is_plain_string<Meta>(v: &UnresolvedValue<Meta>) -> bool {
matches!(v, UnresolvedValue::String(StringOr::Value(_), _))
} Prevention
- Quote identifiers that are meant as strings
- Handle the ClassConstructor variant explicitly in dynamic-value readers
- Type the field as string in the schema so constructors fail validation early
When it happens
Trigger: Calling as_static_str() on UnresolvedValue::ClassConstructor(..) — a BAML field whose value is a class constructor reference (e.g. MyType(...) or the class name where a dynamic value slot accepts it) but is read as a plain string.
Common situations: Using a class reference where a string is expected (e.g. naming a class instead of quoting it), or reading a dynamically-typed field with a string accessor without handling the constructor case.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Could not unify Bool with
- Could not unify Float with
- Expected a boolean
- Expected a map
- Expected a null value
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/851009f7c42677ea.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-lib/baml-types/src/value_expr.rs:533
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")),
}
}
pub fn resolve_bool(&self, ctx: &impl GetEnvVar) -> Result<bool> {
match self.resolve(ctx) {
Ok(ResolvedValue::Bool(b, ..)) => Ok(b),
_ => Err(anyhow::anyhow!("Expected a boolean")),
}
}
View on GitHub (pinned to bd85ce9dee)