BoundaryML/baml · error

system clock is set before the UNIX epoch

Error message

system clock is set before the UNIX epoch

What it means

The WASM sys-op now() returns wall-clock nanoseconds since the UNIX epoch per the Instant.now() contract. If web_time::SystemTime::now() reports a time before the epoch, duration_since returns Err and the code panics with 'system clock is set before the UNIX epoch'. The library intentionally panics because a pre-epoch clock cannot be represented as a valid Instant.

Solutions

  1. Fix the host system clock (sync via NTP) so it reports a post-epoch time
  2. In tests, mock time with values after the UNIX epoch
  3. Wrap time sys-op calls to detect obviously invalid clocks before invoking now()
  4. Report/raise an environment error instead of calling now() when the clock is known bad

Example fix

// before
const t = sys.now(); // panics if clock < epoch
// after
if (Date.now() < 0) throw new Error('system clock before UNIX epoch');
const t = sys.now();
Defensive patterns

Strategy: validation

Validate before calling

if (Date.now() <= 0) throw new Error('Host system clock is before the UNIX epoch; fix system time');

Prevention

When it happens

Trigger: Calling Instant.now() (the time sys-op) while the host/browser reports a system clock earlier than 1970-01-01T00:00:00Z.

Common situations: VMs or embedded devices with unset RTC clocks booting at epoch 0, misconfigured NTP/timezones resetting system time, or test environments faking Date/SystemTime with negative offsets.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


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

Appendix: source

Thrown at baml_language/crates/bridge_wasm/src/wasm_time.rs:111

        .map_err(|e| other("Temporal.ZonedDateTime is not a constructor", &e))?;
    let args = Array::of2(epoch_ns, &JsValue::from_str(timezone));
    Ok(Reflect::construct(&ctor, &args)
        .ok()
        .and_then(|v| v.dyn_into::<Object>().ok()))
}

impl io::IoClassTimeInstant for WasmTime {
    fn now(
        &self,
        _heap: &Arc<BexHeap>,
        _call_id: CallId,
        _ctx: &SysOpContext,
    ) -> SysOpOutput<owned::time::Instant> {
        // Wall-clock time as nanoseconds since the UNIX epoch. Per the
        // `Instant.now()` contract, an unavailable/pre-epoch clock panics.
        let nanos = web_time::SystemTime::now()
            .duration_since(web_time::UNIX_EPOCH)
            .expect("system clock is set before the UNIX epoch")
            .as_nanos();
        SysOpOutput::ok(owned::time::Instant {
            _nanoseconds: Arc::new(num_bigint::BigInt::from(nanos)),
        })
    }
}

impl io::IoNamespaceTime for WasmTime {
    fn system_timezone(
        &self,
        _heap: &Arc<BexHeap>,
        _call_id: CallId,
        _ctx: &SysOpContext,
    ) -> SysOpOutput<String> {
        // Temporal.Now.timeZoneId()
        let result: Result<String, VmRustFnError> = (|| {
            let temporal = temporal()?;
            let now = Reflect::get(&temporal, &"Now".into())

View on GitHub (pinned to bd85ce9dee)