BoundaryML/baml · error

Expected an array

Error message

Expected an array

What it means

In BAML's baml-types crate, ValueExpr::resolve_array resolves a value expression and requires the result to be ResolvedValue::Array. When the expression resolves to any other variant (string, map, number, null, etc.), or resolution fails, the method discards the underlying cause and throws the generic message 'Expected an array'.

Source

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

    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")),
        }
    }

    pub fn resolve_array(&self, ctx: &impl GetEnvVar) -> Result<Vec<ResolvedValue>> {
        match self.resolve(ctx) {
            Ok(ResolvedValue::Array(a, ..)) => Ok(a),
            _ => Err(anyhow::anyhow!("Expected an array")),
        }
    }

    pub fn resolve_map(&self, ctx: &impl GetEnvVar) -> Result<IndexMap<String, ResolvedValue>> {
        match self.resolve(ctx) {
            Ok(ResolvedValue::Map(m, ..)) => Ok(m.into_iter().map(|(k, (_, v))| (k, v)).collect()),
            _ => Err(anyhow::anyhow!("Expected a map")),
        }
    }

    pub fn resolve_numeric(&self, ctx: &impl GetEnvVar) -> Result<String> {
        match self.resolve(ctx) {
            Ok(ResolvedValue::Numeric(n, ..)) => Ok(n),
            _ => Err(anyhow::anyhow!("Expected a numeric value")),
        }
    }

    pub fn resolve_null(&self, ctx: &impl GetEnvVar) -> Result<()> {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Print or resolve the same expression with resolve() to inspect the actual ResolvedValue and confirm its variant before calling resolve_array.
  2. If the value may be a scalar, change the config so the field is a JSON array (e.g. ["gpt-4o"] not "gpt-4o").
  3. If the source is an env var, ensure it is set and the config default wraps values in brackets.
  4. Fix any failing resolve() cause first (env var availability), since its message is currently swallowed.
  5. At your own call sites, match on resolve() and produce a precise error instead of resolve_array.

Example fix

// before (env VALUE = "a,b")
let items = expr.resolve_array(&ctx)?; // Err: Expected an array
// after
// VALUE='["a","b"]' (or config default '["a","b"]') so the expression resolves to an array
let items = expr.resolve_array(&ctx)?;
Defensive patterns

Strategy: validation

Validate before calling

let resolved = expr.resolve(&ctx)?;
if !matches!(resolved, ResolvedValue::Array(_)) {
    bail!("value is not an array: {resolved:?}");
}
let items = expr.resolve_array(&ctx)?;

Type guard

fn is_array(v: &ResolvedValue) -> bool { matches!(v, ResolvedValue::Array(..)) }

Try / catch

match expr.resolve_array(&ctx) {
    Ok(items) => items,
    Err(_) => default_items(), // fallback + log
}

Prevention

When it happens

Trigger: Calling ValueExpr::resolve_array(ctx) on an expression whose resolved value is not an array — e.g. a literal string, map, numeric, or null, or an expression that failed to resolve (env var missing, template error). The catch-all arm swallows the inner resolve(ctx) error.

Common situations: BAML config code that reads a list field (e.g. a list of clients or tests) but the evaluated value came from an env var or single literal that is not a JSON array; a config migration changed a field from list to scalar.

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