nautechsystems/nautilus_trader · critical

Error calling `SystemTime`

Error message

Error calling `SystemTime`

What it means

duration_since_unix_epoch in crates/core/src/time.rs:92 reads the wall clock via wall_clock_now() and computes duration_since(UNIX_EPOCH), unwrapping with expect("Error calling `SystemTime`"). This can only fail if the system clock is set before 1970-01-01 (or the OS clock API misbehaves), which the comments describe as a catastrophic environment condition affecting all time-dependent code, hence the deliberate panic.

Source

Thrown at crates/core/src/time.rs:92

    ATOMIC_CLOCK_STATIC.get_or_init(|| AtomicTime::new(false, UnixNanos::default()))
}

/// Returns the duration since the UNIX epoch based on [`SystemTime::now()`].
///
/// # Panics
///
/// Panics if the system time is set before the UNIX epoch.
#[inline(always)]
#[must_use]
pub fn duration_since_unix_epoch() -> Duration {
    // The expect() is acceptable here because:
    // - SystemTime failure indicates catastrophic system clock issues
    // - This would affect the entire application's ability to function
    // - Alternative error handling would complicate all time-dependent code paths
    // - Such failures are extremely rare in practice and indicate hardware/OS problems
    wall_clock_now()
        .duration_since(UNIX_EPOCH)
        .expect("Error calling `SystemTime`")
}

/// Returns the current wall-clock time as [`SystemTime`].
///
/// Under simulation (`simulation` + `cfg(madsim)`), returns virtual wall-clock
/// time from the madsim deterministic scheduler when called from inside a
/// madsim runtime. When called outside a runtime (e.g. plain `#[rstest]` test
/// bodies), falls back to [`SystemTime::now()`], which under `cfg(madsim)` is
/// libc-intercepted by madsim and resolves to the same real syscall it would
/// in a normal build. Under normal builds, returns [`SystemTime::now()`].
///
/// This is the wall-clock seam. It preserves Unix-epoch semantics (unlike
/// `tokio::time::Instant` which is monotonic and carries no epoch).
#[inline(always)]
#[must_use]
fn wall_clock_now() -> SystemTime {
    #[cfg(not(all(feature = "simulation", madsim)))]
    {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the system clock: run NTP/chrony sync or set the date manually before launching the application.
  2. Replace the RTC battery or configure the device to sync time at boot (e.g. fake-hwclock, systemd-time-wait-sync).
  3. Ensure the host/VM clock is synchronized before starting the trading process; gate startup on time sync if needed.
  4. If the platform cannot guarantee a sane clock, seed the clock from a reliable source at process startup and verify it is past the epoch before calling time APIs.

Example fix

# before (host clock before 1970 due to dead RTC)
./nautilus_trader  # panics: Error calling `SystemTime`
# after
sudo chronyd -q || sudo ntpdate pool.ntp.org   # sync clock first
./nautilus_trader
Defensive patterns

Strategy: fallback

Validate before calling

# Ops/startup gate
import time
now = time.time()
if now < 0:
    raise SystemExit("system clock is before Unix epoch; sync NTP before starting")

Type guard

fn clock_is_sane() -> bool {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .is_ok()
}

Try / catch

// If you must call time APIs on questionable hosts, gate first
if !clock_is_sane() {
    return Err("system clock before Unix epoch; refusing to start");
}
let nanos = nanos_since_unix_epoch();

Prevention

When it happens

Trigger: Calling duration_since_unix_epoch (directly or via nanos_since_unix_epoch, drain_buffer timestamps) on a machine whose system clock is set earlier than the Unix epoch — e.g. a device with a dead RTC battery booting to its epoch default, a VM with a broken clock, or an embedded board with an unset RTC.

Common situations: Embedded/IoT devices and SBCs without battery-backed RTC booting at 1970-01-01; containers/VMs with incorrect clock sync; misconfigured NTP leaving a host far in the past; test environments faking the clock incorrectly.

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