{"record":{"id":"7215ffe3bc768524","repo":"nautechsystems/nautilus_trader","slug":"trusted-host-clock-precedes-the-unix-epoch","errorCode":null,"errorMessage":"Trusted host clock precedes the Unix epoch","messagePattern":"Trusted host clock precedes the Unix epoch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":3585,"sourceCode":"\n    fn release_slot(&self) {\n        *self.in_flight.lock() = None;\n    }\n}\n\nfn replacement_scan_range(from_block: u64, head_block: u64) -> anyhow::Result<RangeInclusive<u64>> {\n    anyhow::ensure!(\n        head_block >= from_block,\n        \"Canonical head {head_block} is behind execution creation block {from_block}\"\n    );\n    let max_end = from_block.saturating_add(MAX_REPLACEMENT_SCAN_BLOCKS - 1);\n    Ok(from_block..=head_block.min(max_end))\n}\n\nfn current_unix_secs() -> anyhow::Result<u64> {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .map_err(|_| anyhow::anyhow!(\"Trusted host clock precedes the Unix epoch\"))\n        .map(|duration| duration.as_secs())\n}\n\nfn validate_payload_operation_batch_size(batch_size: usize) -> anyhow::Result<i64> {\n    anyhow::ensure!(\n        (1..=MAX_PAYLOAD_OPERATION_BATCH_SIZE).contains(&batch_size),\n        \"Payload operation batch size must be between 1 and {MAX_PAYLOAD_OPERATION_BATCH_SIZE}\"\n    );\n    Ok(i64::try_from(batch_size).expect(\"bounded payload batch size fits i64\"))\n}\n\nfn current_execution_hash(\n    intent_id: i64,\n    hashes: &[ExecutionTransactionHashRow],\n) -> anyhow::Result<&ExecutionTransactionHashRow> {\n    let mut current = hashes.iter().filter(|row| row.current);\n    let row = current\n        .next()","sourceCodeStart":3567,"sourceCodeEnd":3603,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L3567-L3603","documentation":"`current_unix_secs` reads the host clock via `SystemTime::now().duration_since(UNIX_EPOCH)` and fails if the system time is before the Unix epoch. The client trusts the host clock for expiry/scan computations, so a pre-epoch clock is treated as a fatal environment error rather than producing a negative/underflowing timestamp.","triggerScenarios":"Any code path calling `current_unix_secs()` (e.g. replacement scans, expiry checks) on a host whose wall clock is set before 1970-01-01 — typically a VM without RTC after power loss, or an embedded/board with uninitialized clock.","commonSituations":"Freshly provisioned VPS/containers with unset system time; Raspberry Pi or IoT boards without battery-backed RTC; misconfigured NTP; test VMs with frozen clocks.","solutions":["Fix the host clock: run NTP sync (`timedatectl set-ntp true`, `chronyc makestep`).","Manually set the date (`date -s @<epoch>`) if NTP is unavailable.","Add clock sanity checks to startup health checks before launching the trader."],"exampleFix":"// before: host clock at 1969\nSystemTime::now().duration_since(UNIX_EPOCH) -> Err\n// after: sync host\n$ sudo timedatectl set-ntp true && timedatectl status","handlingStrategy":"validation","validationCode":"let now = SystemTime::now().duration_since(UNIX_EPOCH)\n    .map_err(|_| anyhow::anyhow!(\"host clock invalid; run NTP sync before starting\"))?;\nanyhow::ensure!(now.as_secs() > 1_600_000_000, \"host clock implausibly old\");","typeGuard":null,"tryCatchPattern":"match current_unix_secs() {\n    Err(e) if e.to_string().contains(\"precedes the Unix epoch\") => {\n        sync_host_clock()?;\n        current_unix_secs()\n    }\n    other => other,\n}","preventionTips":["Enable NTP on all hosts running the trader","Add a clock sanity check to startup health checks","Avoid VMs/images without RTC or configured time sources"],"tags":["clock","environment","system-time","config"],"backgroundTag":"invalid-env-var-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}