BoundaryML/baml · error

: expected int at index

Error message

{fn_name}: expected int at index {index}

What it means

Panic in expect_int when an element of a validated int[] lacks the int tag. Ints are unboxed tagged values, so if as_int() returns None the upstream validation invariant was violated — the array is not actually all-ints.

Solutions

  1. Rebuild the array with only int elements before calling sum.
  2. Verify the declared type of the array matches actual contents.
  3. Report to maintainers — validated int[] should never contain non-ints.
Defensive patterns

Strategy: validation

Validate before calling

// before sum
if (!arr.every(v => Number.isInteger(v))) throw new Error('expected int[] elements');

Type guard

const isIntArray = (a) => Array.isArray(a) && a.every(v => Number.isInteger(v));

Prevention

When it happens

Trigger: Calling sum (or other int-array natives) on an int[] whose contents include a non-int value at extraction time.

Common situations: Arrays assembled through unchecked/dynamic paths; type-checker gaps; mutation of the array after validation.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/a419928d0139fdb0. Report an issue: GitHub.

Appendix: source

Thrown at baml_language/crates/bex_vm/src/package_baml/root.rs:957

            value_type_name(vm, value)
        );
    };
    match vm.get_object(ptr) {
        Object::Float(float) => *float,
        _ => unreachable!(
            "{fn_name}: expected float at index {index}, got {}",
            value_type_name(vm, value)
        ),
    }
}

/// Extracts an `i64` from a validated `int[]` element. Ints are unboxed tagged
/// values, so no heap read is needed; a missing int tag is an upstream invariant
/// violation.
fn expect_int(value: Value, fn_name: &str, index: usize) -> i64 {
    value
        .as_int()
        .unwrap_or_else(|| unreachable!("{fn_name}: expected int at index {index}"))
}

#[cfg(test)]
mod trunc_to_int_tests {
    use super::{BamlPackageBaml, PackageBamlImpl};

    /// `_trunc_to_int` must preserve the old `baml.math.trunc` semantics exactly:
    /// truncate toward zero, saturate to the `i64` range, map NaN to `0`, and
    /// never throw.
    #[test]
    fn trunc_to_int_saturating_semantics() {
        assert_eq!(PackageBamlImpl::_trunc_to_int(3.7), 3);
        assert_eq!(PackageBamlImpl::_trunc_to_int(-3.7), -3);
        assert_eq!(PackageBamlImpl::_trunc_to_int(3.0), 3);
        assert_eq!(PackageBamlImpl::_trunc_to_int(0.0), 0);
        assert_eq!(PackageBamlImpl::_trunc_to_int(-0.0), 0);
        // NaN maps to 0; ±∞ saturate to the i64 bounds (Rust's `as` cast).
        assert_eq!(PackageBamlImpl::_trunc_to_int(f64::NAN), 0);

View on GitHub (pinned to bd85ce9dee)