BoundaryML/baml · error

time-of-day fits in i64

Error message

time-of-day fits in i64

What it means

Internal invariant panic in PlainDateTime.to_plain_time: after Euclidean-modulo reduction to one day (NANOS_PER_DAY), the nanosecond-of-day value must mathematically fit in an i64 (0..86,399,999,999,999). i64::try_from().expect() can only fail if the modulo logic is broken or NANOS_PER_DAY is corrupted.

Source

Thrown at baml_language/crates/bex_vm/src/package_baml/time.rs:342

                    "PlainDateTime.to_plain_date: value is outside the supported year range"
                        .to_string(),
                )
            })?;
        Ok(copy::time::PlainDate { _days: days }.to_value(vm))
    }

    fn to_plain_time(vm: &mut BexVm, plaindatetime: &Value) -> Value {
        let civil = {
            let instance = vm
                .as_instance(plaindatetime)
                .expect("PlainDateTime.to_plain_time: expected PlainDateTime instance");
            view::time::PlainDateTime { instance }._nanoseconds()
        };
        // Euclidean modulo one day is exact regardless of the bigint's
        // magnitude or sign, and the result always fits in an i64.
        let day = num_bigint::BigInt::from(NANOS_PER_DAY);
        let time_ns = ((&*civil % &day) + &day) % &day;
        let time_ns = i64::try_from(time_ns).expect("time-of-day fits in i64");
        copy::time::PlainTime {
            _nanoseconds: time_ns,
        }
        .to_value(vm)
    }

    fn year(plaindatetime: &view::time::PlainDateTime<'_>) -> Result<i64, VmRustFnError> {
        Ok(i64::from(
            civil_datetime(&plaindatetime._nanoseconds(), "PlainDateTime.year")?.year(),
        ))
    }

    fn month(plaindatetime: &view::time::PlainDateTime<'_>) -> Result<i64, VmRustFnError> {
        Ok(i64::from(u8::from(
            civil_datetime(&plaindatetime._nanoseconds(), "PlainDateTime.month")?.month(),
        )))
    }

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Report to maintainers with the exact datetime value that triggered it.
  2. Verify the PlainDateTime instance was not constructed via internal/private field access.
  3. Check for VM/version mismatch; upgrade to the latest bex_vm build.
Defensive patterns

Strategy: fallback

Validate before calling

// Validate the instance was produced by the library before calling to_plain_time()
fn is_valid_plain_datetime(v: &Value, vm: &BexVm) -> bool {
    vm.as_instance(v).map(|i| i.class() == "PlainDateTime").unwrap_or(false)
}

Type guard

fn as_plain_datetime<'a>(vm: &'a BexVm, v: &Value) -> Option<InstanceRef<'a>> {
    vm.as_instance(v).ok().filter(|i| i.class() == "PlainDateTime")
}

Try / catch

// Rust caller: use catch_unwind around VM invocations to convert panics into errors
std::panic::catch_unwind(|| vm_call_to_plain_time(...)).unwrap_or_else(|_| Err(VmError::Internal))

Prevention

When it happens

Trigger: Essentially unreachable from user code; would require a corrupted PlainDateTime nanosecond bigint or a bug in the reduction arithmetic.

Common situations: Hit only during development of the VM itself, or if a bug allows out-of-spec bigint states into PlainDateTime internals.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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