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

  1. Quote the value as a string literal if a plain string is intended, instead of referencing the class
  2. 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()
  3. 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

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


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)