BoundaryML/baml · error · BamlError

type error: expected {expected}, got {got}

Error message

type error: expected {expected}, got {got}

What it means

BamlError::TypeCheck signals an expected runtime type mismatch in the Rust BAML bindings: a BamlValue had a different type than required. The FullTypeName trait supplies the descriptive "got" value, rendering as "type error: expected <X>, got <Y>".

Source

Thrown at languages/rust/baml/src/error.rs:14

use std::collections::HashMap;

/// BAML runtime errors
///
/// Note: This is intentionally minimal. Expand with specific variants
/// (`InitError`, `CallError`, etc.) once the core functionality works.
#[derive(Debug, thiserror::Error, Clone)]
pub enum BamlError {
    /// Internal/unexpected errors - bugs in BAML that should never happen
    #[error("internal error: {0}")]
    Internal(String),

    /// Type check errors - expected runtime failures (type mismatches)
    #[error("type error: expected {expected}, got {got}")]
    TypeCheck { expected: String, got: String },
}

/// Trait for types that can report their full type name for error messages.
/// Used by `BamlValue` variants to provide descriptive "got" values.
pub trait FullTypeName {
    fn full_type_name(&self) -> String;
}

impl BamlError {
    /// Create an internal error for unexpected bugs
    pub fn internal(msg: impl Into<String>) -> Self {
        BamlError::Internal(msg.into())
    }

    /// Create a type check error for expected runtime type mismatches.
    ///
    /// - `T`: The expected type (must implement `BamlTypeName`)

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Compare the 'expected' and 'got' in the message and fix the value's type at the call site.
  2. Regenerate the BAML client after any .baml schema change so generated types match the runtime.
  3. Validate input JSON shapes (e.g. with serde typed structs) before handing them to the BAML runtime.

Example fix

// before
let args = baml_types::BamlMap::from([("user", BamlValue::String("alice".into()))]);
// .baml expects a class User
// after
let args = baml_types::BamlMap::from([("user", BamlValue::Class("User".into(), user_fields))]);
Defensive patterns

Strategy: type-guard

Validate before calling

// validate input JSON shape before calling the runtime
let user: User = serde_json::from_value(input_json)?; // fails early on wrong types

Type guard

matches!(err, BamlError::TypeCheck { .. })
// or narrow a value:
fn as_string(v: &BamlValue) -> Option<&str> { if let BamlValue::String(s) = v { Some(s) } else { None } }

Try / catch

match call {
    Err(BamlError::TypeCheck { expected, got }) => {
        eprintln!("fix input: expected {expected}, got {got}");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling runtime APIs that downcast or match on BamlValue variants (string vs class vs list, etc.) with a value of the wrong type — e.g. passing a string where a class instance or list is expected by a generated function signature.

Common situations: Hand-constructed BamlValue inputs that don't match the .baml function's parameter types; schema drift after editing a .baml file without regenerating the Rust client; passing a JSON value with the wrong shape into the runtime.

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