nautechsystems/nautilus_trader · error

deadline computation overflowed

Error message

deadline computation overflowed

What it means

build_auth_token_for computes the auth-token expiry deadline as 'current unix seconds + DEFAULT_AUTH_TOKEN_TTL_SECS' in i64. It uses checked_add so an i64 overflow anywhere in the sum aborts with this error instead of silently minting a token with a wrapped (far-past) deadline.

Source

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

///
/// # 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
/// for the per-signature `k` nonce.
///
/// The Schnorr binding requires `k` to be drawn from a cryptographic RNG and
/// used at most once per signature; see [`PrivateKey::sign`] for the full
/// contract. The 40-byte draw is reduced modulo the curve order, so the
/// returned scalar is always canonical.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the host system clock (sync via NTP) so 'now' is a realistic unix timestamp
  2. Verify any injected/mock clock source uses sane values
  3. If TTL were configurable, clamp it so now + ttl stays well below i64::MAX

Example fix

// before: relies on wall clock
let now = SystemTime::now();
// after: sanity-check before minting
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
assert!(now.as_secs() < 4_102_444_800, "system clock wildly in the future");
Defensive patterns

Strategy: try-catch

Validate before calling

let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
if now > 1 << 60 { return Err(anyhow!("system clock implausibly far in the future")); }

Type guard

fn plausible_now(t: SystemTime) -> bool {
    t.duration_since(UNIX_EPOCH).map(|d| d.as_secs() < 1 << 60).unwrap_or(false)
}

Try / catch

match build_auth_token_for(&credential) {
    Ok(tok) => tok,
    Err(e) if e.to_string().contains("overflowed") => {
        fix_clock_and_retry();
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The system clock is set to an absurdly far-future value (near i64::MAX seconds, year ~292 billion), so adding the TTL wraps; also reachable via any caller that mints tokens: apply_referral_attribution, is_maker_only_api_key, spawn_ws_consumer, generate_order_status_reports, paginate_fill_reports, build_auth_token_for_round_trips_against_credential.

Common situations: Misconfigured RTC/NTP on the host or container, mocked clocks in tests set to i64 extremes, emulators/VMs with bogus firmware time.

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/5d23b455e2088636. Report an issue: GitHub.