nautechsystems/nautilus_trader · error

system clock is before UNIX epoch

Error message

system clock is before UNIX epoch

What it means

build_auth_token_for timestamps the auth token with the current system time. If SystemTime::now() is before the UNIX epoch — only possible on systems with a clock set earlier than 1970-01-01 — duration_since(UNIX_EPOCH) fails and this error is raised instead of producing a token with a bogus/negative timestamp.

Source

Thrown at crates/adapters/lighter/src/signing/auth_token.rs:121

/// Mint an auth token from a [`crate::common::credential::Credential`] using
/// the default 7-hour TTL and a fresh CSPRNG nonce.
///
/// The token format matches the Go reference's `ConstructAuthToken`. The
/// returned string is the value the WebSocket subscribe handshake sends in
/// the `auth` field of an `account_*` channel subscription.
///
/// # Errors
///
/// Returns the underlying [`crate::common::credential::Credential::private_key`]
/// failure if the secret cannot be decoded, or any [`build_auth_token`]
/// failure (clock-before-epoch or, hypothetically, a breach caused by its own
/// deadline validation).
pub fn build_auth_token_for(
    credential: &crate::common::credential::Credential,
) -> anyhow::Result<SecretString> {
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map_err(|_| anyhow::anyhow!("system clock is before UNIX epoch"))?
        .as_secs();
    let now_i64 = i64::try_from(now)
        .map_err(|_| anyhow::anyhow!("system clock overflowed when converting to i64"))?;
    let deadline = now_i64
        .checked_add(DEFAULT_AUTH_TOKEN_TTL_SECS)
        .ok_or_else(|| anyhow::anyhow!("deadline computation overflowed"))?;
    let sk = credential.private_key()?;
    build_auth_token(
        deadline,
        credential.account_index(),
        credential.api_key_index(),
        &sk,
        fresh_k(),
    )
    .map_err(|e| anyhow::anyhow!("failed to mint Lighter auth token: {e}"))
}

/// Draws a fresh canonical [`Scalar`] from the thread-local CSPRNG suitable

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Synchronize the system clock (NTP: `chronyc makestep`, `ntpdate`, or systemd-timesyncd) and retry.
  2. Check `date -u` — if it shows a pre-1970 date, fix the OS/hypervisor clock configuration.
  3. In containers/VMs, restart the host clock sync or resync after suspend/resume.
  4. Ensure the process is not chrooted into an environment with a fabricated clock.

Example fix

// host shell
$ date -u  # shows e.g. 1969-12-31
$ sudo systemctl enable --now systemd-timesyncd
$ sudo chronyc -a makestep
$ date -u  # now current; retry the client
Defensive patterns

Strategy: validation

Validate before calling

// Guard before calling authenticated APIs
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)
    .map_err(|_| anyhow!("fix system clock before authenticating"))?;

Try / catch

match build_auth_token_for(&credential) {
    Ok(token) => token,
    Err(e) if e.to_string().contains("before UNIX epoch") => {
        eprintln!("system clock is wrong; enable NTP and retry");
        std::process::exit(1);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling any authenticated flow (apply_referral_attribution, is_maker_only_api_key, WS consumer spawn, order status reports, fill report pagination) on a machine whose system clock is set before 1970-01-01.

Common situations: Fresh embedded boards/VMs without RTC and unsynced clocks; containers with wrong system time after host suspend; misconfigured timezones/time manually set far in the past.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/96aa33f362dbb819. Report an issue: GitHub.