BoundaryML/baml · error · VmPanic

baml.panics.StackOverflow

baml.panics.StackOverflow

Error message

stack overflow

What it means

Raised when the VM's call/eval stack exceeds its maximum depth. This protects the interpreter from unbounded recursion exhausting host memory. It is a control-flow limit, not a memory allocation failure.

Source

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

    /// cold overflow path, so the `String` alloc never touches hot code.
    #[error("integer overflow: {message}")]
    IntegerOverflow { message: String },

    // Raised by array and byte-array subscripting, so the message stays generic
    // ("index", not "array index").
    #[error("index out of bounds: {index} of {length}")]
    IndexOutOfBounds { index: i64, length: usize },

    #[error("invalid field access: field {field_index} of {field_count}")]
    InvalidFieldAccess {
        field_index: usize,
        field_count: usize,
    },

    #[error("key not found in map")]
    MapKeyNotFound,

    #[error("stack overflow")]
    StackOverflow,

    #[error("assertion failed")]
    AssertionFailed,

    #[error("unreachable code executed")]
    Unreachable,

    #[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)`.

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Fix the recursion: add or repair the base case so recursion terminates.
  2. Rewrite deep recursion iteratively with an explicit worklist/stack.
  3. Catch `baml.panics.StackOverflow` at a top-level boundary to fail gracefully, though recovery is limited.

Example fix

// before
fn walk(n) { return walk(n); } // no base case
// after
fn walk(n) { if (n <= 0) { return 0; } return walk(n - 1); }
Defensive patterns

Strategy: validation

Validate before calling

// BAML: cap recursion depth up front
fn walk(n: int, depth: int) -> int {
  if (depth > 10_000) { return err("too deep"); }
  ...
}

Try / catch

// BAML
try {
  return recurse(input);
} catch (e: baml.panics.StackOverflow) {
  return err("input too deeply nested");
}

Prevention

When it happens

Trigger: Deeply or infinitely recursive BAML functions, mutual recursion without a base case, or extremely deep non-recursive evaluation (e.g. deeply nested closures/chain calls) exceeding the VM stack limit.

Common situations: Recursive tree/graph traversal without memoization, recursion whose base case depends on data that never terminates, porting code written for a host language with a much larger stack.

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