{"record":{"id":"f03484c3acbf87fb","repo":"ultraworkers/claw-code","slug":"time-should-be-after-epoch","errorCode":null,"errorMessage":"time should be after epoch","messagePattern":"time should be after epoch","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"rust/crates/plugins/src/lib.rs","lineNumber":2309,"sourceCode":"        .chars()\n        .map(|ch| match ch {\n            '/' | '\\\\' | '@' | ':' => '-',\n            other => other,\n        })\n        .collect()\n}\n\nfn describe_install_source(source: &PluginInstallSource) -> String {\n    match source {\n        PluginInstallSource::LocalPath { path } => path.display().to_string(),\n        PluginInstallSource::GitUrl { url } => url.clone(),\n    }\n}\n\nfn unix_time_ms() -> u128 {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .expect(\"time should be after epoch\")\n        .as_millis()\n}\n\nfn copy_dir_all(source: &Path, destination: &Path) -> Result<(), PluginError> {\n    fs::create_dir_all(destination)?;\n    for entry in fs::read_dir(source)? {\n        let entry = entry?;\n        let target = destination.join(entry.file_name());\n        if entry.file_type()?.is_dir() {\n            copy_dir_all(&entry.path(), &target)?;\n        } else {\n            fs::copy(entry.path(), target)?;\n        }\n    }\n    Ok(())\n}\n\nfn update_settings_json(","sourceCodeStart":2291,"sourceCodeEnd":2327,"githubUrl":"https://github.com/ultraworkers/claw-code/blob/08106b0c3771ef5b4a5aa176acccd460e88b7325/rust/crates/plugins/src/lib.rs#L2291-L2327","documentation":"This is a panic, not an error value: unix_time_ms() (plugins/lib.rs:2306) calls SystemTime::now().duration_since(UNIX_EPOCH).expect(...), which unwinds when the system clock reads a time before 1970-01-01 UTC (duration_since returns Err). It is stamped into plugin install records, so any PluginManager install/update path that reaches unix_time_ms() aborts the operation and typically the thread.","triggerScenarios":"PluginManager::install / update (or any code path calling unix_time_ms() to timestamp InstalledPluginRecord) running on a machine whose RTC is set before the epoch: fresh boards with dead CMOS batteries reading 1970/1969, VMs restored from snapshots with regressed clocks, containers pinned via clock namespaces or faketime to negative offsets.","commonSituations":"Embedded devices and Raspberry Pis booting with 1969/1970 clocks before NTP sync; VMs after host hibernate/restore where the guest clock lands pre-epoch; CI with faketime or libfaketime LD_PRELOAD set to a negative offset; deliberately skewed clocks for certificate tests.","solutions":["Fix the clock before running plugin operations: enable NTP/systemd-timesyncd (timedatectl set-ntp true) or set the date manually: date -s '2026-08-17 12:00:00'","On VMs, restore from a snapshot that had time sync enabled, or restart with clock synchronization (Hyper-V/KVM time sync flag on)","Remove faketime/LD_PRELOAD skew for processes that install plugins, or point it to a post-1970 time","As a library fix, replace expect with a safe floor: UNIX_EPOCH.checked_sub_backwards-style handling, e.g. SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis()).unwrap_or(0)"],"exampleFix":"// before (plugins/src/lib.rs:2306) — panics pre-epoch\nfn unix_time_ms() -> u128 {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .expect(\"time should be after epoch\")\n        .as_millis()\n}\n\n// after — clamp instead of panic; a wrong timestamp is better than a crashed install\nfn unix_time_ms() -> u128 {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .map(|d| d.as_millis())\n        .unwrap_or(0)\n}","handlingStrategy":"validation","validationCode":"fn clock_after_epoch() -> bool {\n    std::time::SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .is_ok()\n}\n\n// gate plugin install/update on a sane clock\nif !clock_after_epoch() {\n    return Err(\"system clock is before 1970; run NTP sync before installing plugins\".into());\n}","typeGuard":null,"tryCatchPattern":"// unix_time_ms panics; isolate plugin installs so one bad clock cannot kill the host process\nlet outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    manager.install(source)\n}));\nmatch outcome {\n    Ok(res) => res?,\n    Err(_) => Err(PluginError::Other(\"install panicked (check system clock)\".into())),\n}","preventionTips":["Enable time sync (timedatectl set-ntp true / chrony) on VMs, boards, and CI hosts before running install operations","Avoid faketime/libfaketime negative offsets in processes that install plugins","If you maintain this code, clamp instead of expect: duration_since(UNIX_EPOCH).map(|d| d.as_millis()).unwrap_or(0)"],"tags":["panic","system-clock","epoch","plugins","rust"],"backgroundTag":"system-clock-before-epoch","analyzedSha":"08106b0c3771ef5b4a5aa176acccd460e88b7325","analyzedAt":"2026-08-18T00:29:38.590Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}