BoundaryML/baml · error

offset fits in BAML int

Error message

offset fits in BAML int

What it means

Internal invariant panic when converting a TOML datetime (with a custom numeric offset) into a ZonedDateTime. The offset in minutes comes from the TOML document and is converted to nanoseconds, then wrapped in Value::try_int().expect(); a BAML int is i64-backed, so only an offset outside i64 range can trip it.

Source

Thrown at baml_language/crates/bex_vm/src/package_baml/toml.rs:132

    let time_ns = datetime.time.map(|t| {
        i64::from(t.hour) * NANOS_PER_HOUR
            + i64::from(t.minute) * NANOS_PER_MINUTE
            + i64::from(t.second) * NANOS_PER_SECOND
            + i64::from(t.nanosecond)
    });

    match (days, time_ns, datetime.offset) {
        // Offset Date-Time → ZonedDateTime with a fixed offset.
        (Some(days), Some(time_ns), Some(offset)) => {
            let offset_ns = match offset {
                ::toml::value::Offset::Z => 0,
                ::toml::value::Offset::Custom { minutes } => i64::from(minutes) * NANOS_PER_MINUTE,
            };
            let civil = i128::from(days) * NANOS_PER_DAY + i128::from(time_ns);
            let epoch = civil - i128::from(offset_ns);
            let zoned = super::copy::time::ZonedDateTime {
                _nanoseconds: Arc::new(num_bigint::BigInt::from(epoch)),
                _offset_ns: Value::try_int(offset_ns).expect("offset fits in BAML int"),
                _iana: Value::NULL,
            };
            Ok(zoned.to_value(vm))
        }
        // Local Date-Time → PlainDateTime.
        (Some(days), Some(time_ns), None) => {
            let civil = i128::from(days) * NANOS_PER_DAY + i128::from(time_ns);
            let plain = super::copy::time::PlainDateTime {
                _nanoseconds: Arc::new(num_bigint::BigInt::from(civil)),
            };
            Ok(plain.to_value(vm))
        }
        // Local Date → PlainDate.
        (Some(days), None, None) => Ok(super::copy::time::PlainDate { _days: days }.to_value(vm)),
        // Local Time → PlainTime.
        (None, Some(time_ns), None) => Ok(super::copy::time::PlainTime {
            _nanoseconds: time_ns,
        }

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Validate TOML datetime offsets before conversion (within ±24h).
  2. Sanitize/repair the TOML source file.
  3. Wrap conversion with a catch/abort boundary if ingesting untrusted TOML.
  4. Report to maintainers if a valid RFC 3339 offset triggers it (should be impossible).

Example fix

// before (bad TOML)
ts = 2024-01-01T00:00:00+999999999999:00
// after
ts = 2024-01-01T00:00:00+05:30
Defensive patterns

Strategy: validation

Validate before calling

// Validate TOML datetime offsets before conversion
fn toml_offset_in_range(minutes: i64) -> bool { minutes.abs() <= 24 * 60 }

Try / catch

// Wrap TOML->Value conversion for untrusted files
std::panic::catch_unwind(|| toml_to_zoned(doc)).unwrap_or_else(|_| Err(ConfigError::BadDatetimeOffset))

Prevention

When it happens

Trigger: A TOML document containing an offset datetime whose custom offset minutes yield a nanosecond value beyond i64 range (e.g. astronomically large minutes field in a hand-written/hacked TOML file).

Common situations: Ingesting untrusted or machine-generated TOML config with corrupted datetime offsets; hand-edited config files.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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