BoundaryML/baml · error · VmPanic

baml.panics.DivisionByZero

baml.panics.DivisionByZero

Error message

division by zero: {left:?} / {right:?}

What it means

`VmPanic::DivisionByZero` is a user-visible VM runtime panic raised when an integer division (or modulo-style operation) is performed with a zero divisor. Unlike internal panics, these are part of the language's error model: they carry the operand `Value`s for a readable message and can be intercepted by user `catch` handlers — the `ThrowIfPanic` instruction filters which panics a handler catches versus rethrows.

Source

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

//! these types to heap-allocated exception `Value`s
//! (`panic_to_exception_value` / `error_to_exception_value`) stays in
//! `bex_vm` because it needs VM state (heap, class table).

use thiserror::Error;

use crate::{
    BinOp, CmpOp, SysOpErrorCategory, UnaryOp, Value,
    types::{ObjectType, Type},
};

/// A catchable BAML panic — maps 1:1 to a `baml.panics.*` class.
///
/// These are user-visible runtime errors (division by zero, index out of
/// bounds, etc.) that can be caught by `catch` handlers. The handler's
/// `ThrowIfPanic` instruction filters which panics are caught vs rethrown.
#[derive(Debug, Error, PartialEq, Clone)]
pub enum VmPanic {
    #[error("division by zero: {left:?} / {right:?}")]
    DivisionByZero { left: Value, right: Value },

    /// An `int` (i63) arithmetic operation overflowed the representable
    /// range `[INT_MIN, INT_MAX]`. Carries a human-readable description of
    /// the operation (e.g. `"4611686018427387903 + 1"`); built only on the
    /// 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,

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Guard the divisor before dividing: branch on `right == 0` and return a default/error value instead of dividing.
  2. Wrap the division in a `catch` handler in BAML so `ThrowIfPanic` catches DivisionByZero and your handler recovers.
  3. Validate user/config-derived inputs at the boundary, rejecting zero where a denominator is required.
  4. Log the operands (they're included in the panic) to find where the zero value originates.

Example fix

// before (BAML)
let ratio = total / count;
// after
let ratio = if count == 0 { 0 } else { total / count };
Defensive patterns

Strategy: try-catch

Validate before calling

// check the divisor before dividing (host-side guard)
if right.as_int() == Some(0) { return Err("denominator must be non-zero"); }

Try / catch

// in BAML: catch the panic and recover
catch (e) {
  // ThrowIfPanic matches VmPanic::DivisionByZero here
  fallback_value()
} { ratio = total / count; }

Prevention

When it happens

Trigger: Executing a BAML division instruction `left / right` where `right` evaluates to an int value of 0; e.g. `x / y` where y comes from user input, an empty-collection count, or a computed denominator that reaches 0 at runtime.

Common situations: Computing averages/percentages where a collection is empty; user-supplied numeric input of 0; off-by-one logic producing a zero denominator; unguarded config-derived values used as divisors.

Related errors


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