BoundaryML/baml · warning · VmPanic

baml.panics.Exit

baml.panics.Exit

Error message

baml.sys.exit({code})

What it means

A clean process-termination request raised by `baml.sys.exit(code)`. It is catchable in user code as `baml.panics.Exit` — patterned after Python's `SystemExit` — so code can intercept it for cleanup or testing. If nothing catches it, the engine surfaces the code as `EngineError::Exit` and the host terminates with it; BAML's i64 int is narrowed to i32 by the host for `std::process::exit`.

Source

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

    #[error("operation cancelled")]
    Cancelled,

    /// A user-caused panic from `baml.sys.panic`, and the stdlib's panic of
    /// record for a user-violated native invariant (e.g. a reflection kind
    /// view's `_ty` field overwritten with a type of a different kind).
    #[error("baml.sys.panic: {message}")]
    UserPanic { message: String },

    /// A clean process-termination request from `baml.sys.exit(code)`.
    ///
    /// Catchable in user code as `baml.panics.Exit` — patterned after
    /// Python's `SystemExit`: code can intercept it for cleanup or
    /// testing, and if nothing catches it the engine surfaces the code
    /// as `EngineError::Exit` and the host terminates with it.
    ///
    /// BAML `int` is `i64`, so the signal carries the full value the
    /// user wrote; the host narrows to `i32` for `std::process::exit`.
    #[error("baml.sys.exit({code})")]
    Exit { code: i64 },

    /// The graceful-ish way to handle potential OOM errors, instead of hard-crashing.
    #[error("memory allocation failed: {message}")]
    AllocFailure { message: String },

    /// A required host resource is unavailable — e.g. the OS entropy source
    /// returned an error in a sandboxed runtime. Catchable so user code can
    /// fall back gracefully instead of aborting the host process.
    #[error("host resource '{resource}' unavailable: {message}")]
    HostUnavailable { resource: String, message: String },

    /// The right operand of a bigint shift (`<<` / `>>`) was negative.
    /// Catchable because the count is a runtime `bigint` and the type
    /// system can't rule out negative values.
    #[error("negative bit shift: {message}")]
    NegativeBitShift { message: String },

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. If you did not intend termination, remove or guard the `baml.sys.exit` call.
  2. Catch `baml.panics.Exit` to intercept the request for cleanup or testing instead of letting the process end.
  3. Use conventional exit codes (0 success, non-zero failure) so the host's i32 narrowing produces meaningful process status.

Example fix

// before
baml.sys.exit(1); // hard-terminates the host
// after
try {
  baml.sys.exit(1);
} catch (e: baml.panics.Exit) {
  log("cleanup before exit");
  rethrow;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// BAML: decide explicitly whether to exit or return
if (fatal) { return err(code); } // instead of baml.sys.exit(code) in library code

Try / catch

// BAML
try {
  main();
} catch (e: baml.panics.Exit) {
  cleanup();
  rethrow; // let the host exit with e.code
}

Prevention

When it happens

Trigger: BAML code calls `baml.sys.exit(n)` with any i64 code; the panic propagates unless caught by a `baml.panics.Exit` handler, in which case execution continues after the catch site.

Common situations: CLI-style BAML programs exiting with a status code on validation failure, tests intercepting exit requests to assert the code, top-level scripts terminating early on missing input.

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