{"record":{"id":"8b32d96ab8a10c0b","repo":"stalwartlabs/stalwart","slug":"invalid-system-time-panicking-to-avoid-data-corru","errorCode":null,"errorMessage":"Invalid system time, panicking to avoid data corruption","messagePattern":"Invalid system time, panicking to avoid data corruption","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/common/src/config/inner.rs","lineNumber":58,"sourceCode":"impl Data {\n    pub async fn parse(bp: &mut Bootstrap) -> Self {\n        // Parse certificates\n        let mut certificates = AHashMap::new();\n        let mut subject_names = AHashSet::new();\n        parse_certificates(bp, &mut certificates, &mut subject_names).await;\n        if subject_names.is_empty() {\n            subject_names.insert(\"localhost\".into());\n        }\n\n        // Build and test snowflake id generator\n        let node_id = bp.node_id();\n        if node_id > MAX_NODE_ID {\n            panic!(\"Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid data corruption\");\n        }\n        SnowflakeIdGenerator::set_node_id(node_id as u64);\n        let id_generator = SnowflakeIdGenerator::new();\n        if !id_generator.is_valid() {\n            panic!(\"Invalid system time, panicking to avoid data corruption\");\n        }\n\n        // Initialize apps\n        let applications = WebApplications::new();\n        applications.reload(bp).await;\n\n        let blocked_ips = BlockedIps::parse(bp).await;\n        let lookup_stores = LookupStores::build(bp).await;\n\n        Data {\n            spam_classifier: ArcSwap::from_pointee(SpamClassifier::default()),\n            tls_certificates: ArcSwap::from_pointee(certificates),\n            tls_self_signed_cert: build_self_signed_cert(\n                subject_names\n                    .into_iter()\n                    .map(Into::into)\n                    .collect::<Vec<_>>(),\n            )","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/common/src/config/inner.rs#L40-L76","documentation":"Right after setting the snowflake node id, the parser constructs a SnowflakeIdGenerator and calls is_valid(); a false result means the system clock produced an id that fails the generator's validity check (typically a clock set before/outside the epoch or an obviously bogus time). Since snowflake ids derive from wall-clock time, running with an invalid clock risks duplicate or regressing ids, so the server panics at startup to avoid data corruption.","triggerScenarios":"Starting the server when the host system time is invalid — set before the snowflake epoch, reset to epoch/1970, or otherwise failing SnowflakeIdGenerator::is_valid(). `Config::parse` panics during the id-generator self-test.","commonSituations":"Fresh VMs or containers whose RTC is unset (clock at 1970), VMs resuming with drifted clocks, misconfigured NTP, or embedded devices without a battery-backed clock.","solutions":["Fix the system clock before starting the server: enable and verify NTP sync (`timedatectl set-ntp true`, `chronyc tracking`).","Manually set a correct current time (`date -s` / hypervisor time sync) if NTP is unavailable, then restart.","If running in a container, ensure the host clock is correct since containers share it; restart after host clock repair."],"exampleFix":"// before: container started with host clock at 1970\n// after (host):\n// $ sudo timedatectl set-ntp true\n// $ timedatectl status  # verify 'System clock synchronized: yes'\n// then restart the server","handlingStrategy":"validation","validationCode":"// before starting the server, verify the clock:\nuse std::time::{SystemTime, UNIX_EPOCH};\nlet now = SystemTime::now().duration_since(UNIX_EPOCH).expect(\"system clock before Unix epoch\");\nassert!(now.as_secs() > 1_600_000_000, \"system clock looks unset; enable NTP\");","typeGuard":"fn clock_is_sane() -> bool {\n    std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)\n        .map(|d| d.as_secs() > 1_600_000_000).unwrap_or(false)\n}","tryCatchPattern":"// panic at startup is not catchable; run the server under a supervisor that logs the panic and restarts after clock repair","preventionTips":["Enable NTP/time sync on all hosts and VMs running the server.","For containers, fix the host clock — containers inherit it.","Add a startup health check that verifies wall-clock sanity before launching services."],"tags":["config","clock","snowflake-id","startup"],"backgroundTag":"invalid-system-clock","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}