{"record":{"id":"7c6bccd86790190e","repo":"nautechsystems/nautilus_trader","slug":"time-went-backwards","errorCode":null,"errorMessage":"Time went backwards","messagePattern":"Time went backwards","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/hyperliquid/src/signing/nonce.rs","lineNumber":51,"sourceCode":"    /// Create from Unix milliseconds.\n    pub fn from_millis(ms: i128) -> Self {\n        Self(ms)\n    }\n\n    /// Get as milliseconds.\n    pub fn as_millis(self) -> i128 {\n        self.0\n    }\n\n    /// Current time in milliseconds.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the system time is before the Unix epoch.\n    pub fn now_millis() -> Self {\n        let now = SystemTime::now()\n            .duration_since(UNIX_EPOCH)\n            .expect(\"Time went backwards\");\n        Self::from_millis(now.as_millis() as i128)\n    }\n}\n\nimpl Display for TimeNonce {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.0)\n    }\n}\n\n/// Nonce policy configuration for Hyperliquid.\n#[derive(Debug, Clone)]\npub struct NoncePolicy {\n    pub past_ms: i64,\n    pub future_ms: i64,\n    pub keep_last_n: usize,\n}\n","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/hyperliquid/src/signing/nonce.rs#L33-L69","documentation":"TimeNonce::now_millis reads the system clock and expects it to be after the Unix epoch (1970-01-01 UTC). If the OS clock reports a time before the epoch, duration_since fails and the expect panics. Nonce generation for signed Hyperliquid requests must be monotonic wall-clock milliseconds, so a backwards clock makes signing impossible.","triggerScenarios":"Calling now_millis (directly or via any order/signing flow) while the host system clock is set before 1970-01-01T00:00:00Z, e.g. after RTC battery failure, VM resume with unsynced clock, or container with wrong time source.","commonSituations":"Embedded/bare-metal hosts without RTC; Docker containers starting before NTP sync; VM snapshots restoring an old clock; misconfigured system timezone/date during testing.","solutions":["Fix the system clock (ntpdate/chrony/systemd-timesyncd or `date -s`) so it is after the Unix epoch.","Enable automatic time sync on the host/VM/container before running the trader.","Upgrade/patch if the platform provides a clock that can legitimately regress; otherwise monitor clock before starting."],"exampleFix":"// before\nlet nonce = TimeNonce::now_millis(); // panics if clock < epoch\n\n// after (guard at startup)\nlet now = SystemTime::now().duration_since(UNIX_EPOCH)\n    .expect(\"system clock must be after Unix epoch; fix host time sync\");","handlingStrategy":"validation","validationCode":"// startup guard\nlet epoch_ok = SystemTime::now().duration_since(UNIX_EPOCH).is_ok();\nif !epoch_ok { panic!(\"fix system clock before starting trader\"); }","typeGuard":"fn clock_is_sane() -> bool {\n    SystemTime::now().duration_since(UNIX_EPOCH).is_ok()\n}","tryCatchPattern":"// boundary: convert panic to error at FFI/task edge\nstd::panic::catch_unwind(|| TimeNonce::now_millis())\n    .map_err(|_| anyhow!(\"system clock before Unix epoch\"))","preventionTips":["Enable NTP/chrony/systemd-timesyncd on all trading hosts.","Add a startup health check verifying the clock is past the epoch and roughly correct.","Monitor clock skew in containers/VMs and alert before it breaks signing."],"tags":["rust","panic","system-clock","time","signing"],"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"}