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
- Fix the system clock: run NTP/chrony sync or set the date manually before launching the application.
- Replace the RTC battery or configure the device to sync time at boot (e.g. fake-hwclock, systemd-time-wait-sync).
- Ensure the host/VM clock is synchronized before starting the trading process; gate startup on time sync if needed.
- 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
- Run NTP/chrony on all hosts and gate startup on successful time sync.
- Replace RTC batteries on embedded devices and sync time at boot.
- Verify VM/container clock sync in deployment health checks.
- Check the clock once at process startup before any time-dependent work.
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
- Time went backwards
- System time overflow: value exceeds u64::MAX nanoseconds
- heartbeat request timeout should fit in an instant
- in-flight mutex poisoned
- wallet balance mutex poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7b97e129508147c8.
Report an issue: GitHub.