BoundaryML/baml · error · AccessError

Type mismatch: expected

Error message

Type mismatch: expected {expected}, got {actual}

What it means

AccessError::TypeMismatch is returned by bex_heap accessors when a handle points to a live object but of the wrong type for the requested operation — e.g. reading a struct field from an object that is actually a list. `expected` names the required type and `actual` carries the debug representation of what was found.

Solutions

  1. Match on the Value/Object variant and handle each type explicitly before calling typed accessors
  2. Use type-checking helpers on the heap before narrowing
  3. Fix the producer of the value so the correct type is stored
  4. Log `actual` from the error to find where the wrong-typed value originated

Example fix

// before
let s = heap.get_string(value)?; // value is actually an Int
// after
match value {
    Value::String(h) => heap.get_string(h)?,
    other => return Err(AccessError::TypeMismatch { expected: "String", actual: format!("{:?}", other) }),
}
Defensive patterns

Strategy: type-guard

Validate before calling

if !matches!(value, Value::String(_)) {
    return Err(AccessError::TypeMismatch { expected: "String", actual: format!("{:?}", value) });
}

Type guard

fn is_string(v: &Value) -> bool { matches!(v, Value::String(_)) }

Try / catch

match heap.get_string(handle) {
    Ok(s) => s,
    Err(AccessError::TypeMismatch { expected, actual }) => { log::warn!("wanted {expected}, got {actual}"); coerce_or_default(); },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling a typed accessor (get_string, get_field, call_function, etc.) with a Value/HeapPtr whose runtime type differs from the accessor's expectation, often after an unchecked downcast.

Common situations: Script values flowing into native code with assumed types; schema changes to object layouts; skipping the type check branch of a match on Value and falling through to a typed accessor.

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

Appendix: source

Thrown at baml_language/crates/bex_heap/src/accessor.rs:18

//! Safe accessor API for external code to read heap objects.
//!
//! External code cannot safely hold bare `HeapPtr` values across GC. This
//! module provides an API that takes a `PermitProof<'_>` (obtained from any
//! held `ActiveHeapPermit<T>`) to witness GC-exclusion at the type level.

use baml_type::RuntimeTy;
use bex_external_types::{BexExternalAdt, BexExternalValue, WeakHeapRef};
use bex_vm_types::{HeapPtr, Object, PermitProof, Value};

use crate::BexHeap;

#[derive(Debug, PartialEq, thiserror::Error, Clone)]
pub enum AccessError {
    #[error("Invalid handle: expected {expected}")]
    InvalidHandle { expected: &'static str },

    #[error("Type mismatch: expected {expected}, got {actual}")]
    TypeMismatch {
        expected: &'static str,
        actual: String,
    },

    #[error("Field not found: expected {expected}")]
    FieldNotFound { expected: String },

    #[error("Function not found: {expected}")]
    FunctionNotFound { expected: String },

    #[error("Cannot convert to owned: {reason}")]
    CannotConvertToOwned { reason: String },
}

pub enum BexValue<'a> {
    ExternalValue(&'a BexExternalValue),
    HeapPtr(&'a HeapPtr),

View on GitHub (pinned to bd85ce9dee)