BoundaryML/baml · error · VmRustFnError

thrown value

Error message

thrown value

What it means

This error variant (VmError::Thrown { value, profiler_kind }) displays as "thrown value" and represents a pre-built exception Value to be thrown directly as a catchable error. Native functions use it to throw user-defined class instances such as baml.json.ParseError without going through the VmPanic/VmBamlError enumeration machinery.

Solutions

  1. Catch the thrown value and inspect it — it is a real class instance (e.g. baml.json.ParseError) with useful fields.
  2. Validate/normalize JSON input before calling parsing functions so the throw never happens.
  3. Note the message is generic by design ("thrown value"); enable profiler-kind/error logging for more context.
  4. Handle the specific exception class name in your catch logic.

Example fix

// before: raw parse throws and escapes
let data = baml.json.Parse(input)

// after: guard the input first
let data = input.trim().len() > 0 && is_valid_json(input)
  ? baml.json.Parse(input)
  : null
Defensive patterns

Strategy: validation

Validate before calling

// Check JSON validity before invoking the parsing native function
fn looks_like_json(s: &str) -> bool {
    let t = s.trim();
    !t.is_empty()
        && ((t.starts_with('{') && t.ends_with('}'))
            || (t.starts_with('[') && t.ends_with(']'))
            || (t.starts_with('"') && t.ends_with('"')))
}

Try / catch

match vm_result {
    Err(BexError::Thrown { value, .. }) => {
        if let Some(pe) = value.as_instance_of("baml.json.ParseError") {
            eprintln!("JSON parse error: {:?}", pe);
        }
    }
    other => other?,
}

Prevention

When it happens

Trigger: A native function (e.g. JSON parsing) needs to throw a user-defined exception instance; the VM raises it as a catchable error value; when uncaught it surfaces with the generic message "thrown value".

Common situations: Parsing malformed JSON in BAML and baml.json.ParseError escaping without a catch handler; host-defined exception classes thrown by native helpers; the generic message hides the real cause until the thrown Value is inspected.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at baml_language/crates/bex_vm_types/src/errors.rs:477

}

/// An error returned by a Rust function. Will generally be turned into a [`VmError`].
/// This is separate from [`VmError`] so native Rust functions can return standard errors
/// without needing to handle heap allocation.
#[derive(Debug, Error, PartialEq, Clone)]
pub enum VmRustFnError {
    #[error("{0}")]
    Panic(#[from] VmPanic),
    #[error("{0}")]
    BamlError(#[from] VmBamlError),
    #[error("{0}")]
    InternalError(#[from] VmInternalError),
    /// A pre-built exception `Value` to throw directly as a catchable error.
    ///
    /// Used by native functions that need to throw user-defined class instances
    /// (e.g. `baml.json.ParseError`) without going through the
    /// `VmPanic` / `VmBamlError` enumeration machinery.
    #[error("thrown value")]
    Thrown {
        value: Value,
        profiler_kind: ProfilerErrorKind,
    },
}

impl VmRustFnError {
    #[must_use]
    pub const fn thrown_fresh(value: Value) -> Self {
        Self::Thrown {
            value,
            profiler_kind: ProfilerErrorKind::Fresh,
        }
    }

    #[must_use]
    pub const fn thrown_rethrow(value: Value) -> Self {
        Self::Thrown {

View on GitHub (pinned to bd85ce9dee)