nautechsystems/nautilus_trader · error · anyhow::Error

Timer '{name}' first event time exceeds UnixNanos range

Error message

Timer '{name}' first event time exceeds UnixNanos range

What it means

NautilusTrader's clock validates that a timer's first fire time fits in the UnixNanos (i64 nanoseconds) domain. When registering a timer whose start_time_ns plus interval_ns would overflow the nanosecond range, the checked addition fails and this error is returned instead of silently wrapping. It protects downstream time arithmetic from overflow-corrected garbage timestamps.

Source

Thrown at crates/common/src/clock.rs:857

    fire_immediately: Option<bool>,
    ts_now: UnixNanos,
) -> anyhow::Result<(Ustr, UnixNanos, Option<UnixNanos>, bool, bool)> {
    check_valid_string_utf8(name, stringify!(name))?;
    check_positive_u64(interval_ns.as_u64(), stringify!(interval_ns))?;

    let name = Ustr::from(name);
    let allow_past = allow_past.unwrap_or(true);
    let fire_immediately = fire_immediately.unwrap_or(false);

    let start_time_ns = start_time_ns
        .filter(|start_time_ns| *start_time_ns != 0)
        .unwrap_or(ts_now);

    let next_event_time = if fire_immediately {
        start_time_ns
    } else {
        start_time_ns.checked_add(interval_ns).ok_or_else(|| {
            anyhow::anyhow!("Timer '{name}' first event time exceeds UnixNanos range")
        })?
    };

    if !allow_past && next_event_time < ts_now {
        anyhow::bail!(
            "Timer '{name}' next event time {} would be in the past (current time is {ts_now})",
            next_event_time.to_rfc3339(),
        );
    }

    if let Some(stop_time) = stop_time_ns {
        if stop_time <= start_time_ns {
            anyhow::bail!(
                "Timer '{name}' stop time {} must be after start time {}",
                stop_time.to_rfc3339(),
                start_time_ns.to_rfc3339(),
            );
        }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Reduce the timer interval so start_time_ns + interval_ns stays below ~9.2e18 nanoseconds
  2. Verify units: interval_ns must already be in nanoseconds; convert seconds/ms with Duration::from_secs(...).as_nanos() as u64
  3. If the intent is a far-future/never-firing timer, use a smaller sentinel interval or cancel the timer explicitly instead
  4. Check that start_time_ns itself is a plausible current-time UnixNanos value and not already near the limit

Example fix

// before
clock.set_timer_ns("poll", u64::MAX, None, None, None, false, false, None)?;
// after
let one_hour_ns = std::time::Duration::from_secs(3600).as_nanos() as u64;
clock.set_timer_ns("poll", one_hour_ns, None, None, None, false, false, None)?;
Defensive patterns

Strategy: validation

Validate before calling

let max_interval: u64 = (i64::MAX as u128 - start_time_ns as u128) as u64;
assert!(interval_ns <= max_interval, "timer interval overflows UnixNanos");

Try / catch

match clock.set_timer_ns(name, interval, None, None, None, false, false, None) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("exceeds UnixNanos range") => {
        log::error!("interval too large for nanosecond domain: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling set_time_alert_ns/set_timer_ns with an interval_ns so large that start_time_ns + interval_ns exceeds i64::MAX nanoseconds (~year 2262); e.g. passing an interval expressed in milliseconds or seconds by mistake, or an absurdly long duration near u64/i64 nanosecond limits.

Common situations: Unit-conversion mistakes (passing nanoseconds constant like 86_400_000_000_000 multiplied again, or using Duration::MAX-style values), scheduling timers intended to 'never fire' by using a huge interval, misconfigured timeout config parsed into the wrong unit.

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 nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/423b6c7406726044. Report an issue: GitHub.