BoundaryML/baml · error · anyhow::Error

Expected a {err_msg}, got: {}

Error message

Expected a {err_msg}, got: {}

What it means

This error comes from a macro that implements type-narrowing methods on TypeGeneric<T>. When a method that only makes sense for certain type variants (e.g. primitives, classes) is called on a variant that does not support it (and it is not a recursive type alias that can be expanded), the macro bails with "Expected a <what>, got: <actual>". It signals that the caller assumed the field type had a shape it does not have.

Source

Thrown at engine/baml-lib/baml-types/src/ir_type/mod.rs:101

            TypeGeneric::Arrow(_, _) => "function",
            TypeGeneric::Union(_, _) => "union",
        }
    }
}

macro_rules! impl_as_variant {
    ($method_name:ident, $variant:pat, $err_msg:literal) => {
        pub fn $method_name<U: TypeLookupsMeta<T>>(
            self,
            lookup: &U,
        ) -> anyhow::Result<TypeGeneric<T>> {
            match self {
                $variant => Ok(self),
                TypeGeneric::RecursiveTypeAlias { name, .. } => {
                    let expanded_type = TypeLookupsMeta::<T>::expand_recursive_type(lookup, &name)?;
                    expanded_type.$method_name::<U>(lookup)
                }
                _ => anyhow::bail!(concat!("Expected a ", $err_msg, ", got: {}"), self),
            }
        }
    };
}

impl<T: MetaSuffix> TypeGeneric<T> {
    impl_as_variant!(resolve_map, TypeGeneric::Map(..), "map type");
    impl_as_variant!(resolve_list, TypeGeneric::List(..), "list type");
    impl_as_variant!(resolve_enum, TypeGeneric::Enum { .. }, "enum type");
    impl_as_variant!(resolve_class, TypeGeneric::Class { .. }, "class type");
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, strum::Display)]
pub enum StreamingMode {
    NonStreaming,
    Streaming,
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Inspect the actual type in the error message and match on the correct TypeGeneric variant before calling the narrowing method.
  2. Expand recursive type aliases first (expand_recursive_type) so the method can recurse instead of hitting the fallback bail.
  3. If you control the schema, align the field's declared type with what the calling code expects.
  4. Use pattern matching (match on TypeGeneric variants) instead of assuming a single variant.

Example fix

// before
let cls = field_type.as_class()?; // panics/bails if field is a union
// after
match field_type {
    TypeGeneric::Class(_) => { /* handle class */ }
    TypeGeneric::Union(_) => { /* handle union explicitly */ }
    _ => anyhow::bail!("unexpected field type"),
}
Defensive patterns

Strategy: type-guard

Validate before calling

if !matches!(field_type, TypeGeneric::Class(_) | TypeGeneric::Primitive(_)) { return Err(anyhow!("unexpected variant")); }

Type guard

fn is_named_type(t: &TypeGeneric<Meta>) -> bool { matches!(t, TypeGeneric::Class(_) | TypeGeneric::Enum(_)) }

Try / catch

match field_type.as_class_if_supported() { Ok(c) => handle(c), Err(e) => log::warn!("type shape mismatch: {}", e) }

Prevention

When it happens

Trigger: Calling a TypeGeneric narrowing/inspection method (generated by this macro) on a type whose variant does not match what the method expects, e.g. treating a union, list, or map as a named class, or inspecting a field type before recursive aliases are expanded.

Common situations: BAML schema code or generated clients traversing IR types and assuming a field is e.g. a class or primitive when the schema actually declares a union/list; schema changes that changed a field's type while downstream code assumed the old shape.

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