BoundaryML/baml · info · EngineError
baml.sys.exit({code})
Error message
baml.sys.exit({code}) What it means
Not a failure: a structured signal raised when BAML code calls `baml.sys.exit(code)`, requesting clean process termination. The error variant carries the full i64 exit code; the embedding caller is expected to honor it as the process exit status, clamping to the shell's range (typically 0..=255 on Unix).
Source
Thrown at baml_language/crates/bex_engine/src/lib.rs:839
#[error("{}", format_vm_internal_error(source, trace))]
TracedVmInternalError {
source: bex_vm::errors::VmInternalError,
trace: Vec<bex_vm::StackFrame>,
},
/// Either a BAML panic or a BAML error value.
#[error("{}", format_unhandled_throw(value, trace))]
UnhandledThrow {
value: Box<BexExternalValue>,
trace: Vec<bex_vm::StackFrame>,
},
/// Clean process-termination request from `baml.sys.exit(code)`.
/// The caller is expected to honor this as the process exit code.
/// BAML `int` is `i64`, so the signal carries the full value; the
/// caller clamps into its shell's range (typically 0..=255 on Unix).
#[error("baml.sys.exit({code})")]
Exit { code: i64 },
#[error("Cannot convert object of type {type_name}")]
CannotConvert { type_name: String },
#[error("Type mismatch: {message}")]
TypeMismatch { message: String },
#[error("Schema inconsistency: {message}")]
SchemaInconsistency { message: String },
#[cfg(feature = "heap_debug")]
#[error("Snapshot not possible for type: {type_name}")]
CannotSnapshot { type_name: String },
#[error("A function call with ID {call_id} is already in progress")]
DuplicateCallId { call_id: CallId },
View on GitHub (pinned to bd85ce9dee)
Solutions
- Catch/handle this variant in the host and exit the process with the given code (clamped to 0..=255)
- If exit is unexpected, audit the BAML code for baml.sys.exit calls
- In server embeddings, translate it into a request-scoped abort rather than killing the process
Example fix
// host code (rust, conceptual)
// before: treats it as generic failure
Err(e) => panic!("{}", e),
// after
Err(EngineError::Exit { code }) => std::process::exit(code.clamp(0, 255) as i32), Defensive patterns
Strategy: try-catch
Try / catch
match result {
Err(EngineError::Exit { code }) => std::process::exit(code.clamp(0, 255) as i32),
Ok(v) => use(v),
Err(e) => handle(e),
} Prevention
- Treat Exit as control flow, not failure, in host glue
- Audit BAML scripts for baml.sys.exit before embedding in servers
- Clamp the i64 code to the OS exit-status range
When it happens
Trigger: A BAML function calls `baml.sys.exit(code)` and the engine surfaces it as this variant instead of terminating the host process directly.
Common situations: CLI-style BAML scripts that want to set their Unix exit status; tests that trigger early-exit paths; embedding the engine in a server where exit must be intercepted.
Related errors
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/b9b2961a3f660bb3.
Report an issue: GitHub.