BoundaryML/baml · error · VmError

uncaught throw: {0:?}

Error message

uncaught throw: {0:?}

What it means

VmError::Thrown wraps a VmThrown value representing a catchable throw (panic or error value) inside the BAML VM that was never caught. It is primarily an internal unwinding signal; when it surfaces to the user it means an exception raised in BAML code escaped without any matching catch handler.

Source

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

            value,
            profiler_kind: ProfilerErrorKind::Rethrow,
            language_is_rethrow,
            origin: VmUnwindOrigin::unresolved(source),
        }
    }

    #[must_use]
    pub const fn with_origin(mut self, origin: VmUnwindOrigin) -> Self {
        self.origin = origin;
        self
    }
}

/// Any kind of virtual machine error.
#[derive(Debug, Error, PartialEq, Clone)]
pub enum VmError {
    /// Catchable (panics and error values) — internal signal for exception unwinding.
    #[error("uncaught throw: {0:?}")]
    Thrown(VmThrown),
    /// An exception that escaped all catch handlers, with captured stack trace.
    #[error("uncaught throw: {value:?}")]
    ThrownUnhandled {
        value: Value,
        trace: Vec<StackFrame>,
    },
    /// Fatal VM errors
    #[error("{0}")]
    InternalError(#[from] VmInternalError),
    /// Fatal VM error with captured stack trace.
    /// Produced by `exec()` wrapper from `InternalError`.
    #[error("{}", format_internal_error(source, trace))]
    TracedInternalError {
        source: VmInternalError,
        trace: Vec<StackFrame>,
    },
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Wrap the failing BAML expression/call in a catch handler appropriate to the thrown value type.
  2. Inspect the debug-formatted VmThrown in the message to see exactly what was thrown and from where.
  3. Fix the root cause (the operation that threw) once identified from the thrown value.
  4. Add top-level error handling in the host when calling BAML functions so uncaught throws are reported cleanly.

Example fix

// before: no handler
let r = risky();

// after
let r = catch risky() {
  case e => "fallback"
}
Defensive patterns

Strategy: try-catch

Try / catch

match vm_result {
    Err(BexError::Thrown(thrown)) => {
        eprintln!("uncaught VM throw: {:?}", thrown);
    }
    other => other?,
}

Prevention

When it happens

Trigger: BAML code executes a throw/panic and no enclosing catch block matches; native functions raise catchable errors that bubble to the top of the VM; a thrown Value (e.g. a user-defined class instance) is not intercepted by any handler.

Common situations: Omitting a catch handler for fallible BAML logic; a runtime or client error (e.g. LlmClient failure) being re-thrown as a VM throw; user-defined exception classes thrown in helpers and never caught at the call site.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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