ultraworkers/claw-code · critical
time should be after epoch
Error message
time should be after epoch
What it means
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.
Source
Thrown at rust/crates/plugins/src/lib.rs:2309
.chars()
.map(|ch| match ch {
'/' | '\\' | '@' | ':' => '-',
other => other,
})
.collect()
}
fn describe_install_source(source: &PluginInstallSource) -> String {
match source {
PluginInstallSource::LocalPath { path } => path.display().to_string(),
PluginInstallSource::GitUrl { url } => url.clone(),
}
}
fn unix_time_ms() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("time should be after epoch")
.as_millis()
}
fn copy_dir_all(source: &Path, destination: &Path) -> Result<(), PluginError> {
fs::create_dir_all(destination)?;
for entry in fs::read_dir(source)? {
let entry = entry?;
let target = destination.join(entry.file_name());
if entry.file_type()?.is_dir() {
copy_dir_all(&entry.path(), &target)?;
} else {
fs::copy(entry.path(), target)?;
}
}
Ok(())
}
fn update_settings_json(View on GitHub (pinned to 08106b0c37)
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)
Example fix
// before (plugins/src/lib.rs:2306) — panics pre-epoch
fn unix_time_ms() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("time should be after epoch")
.as_millis()
}
// after — clamp instead of panic; a wrong timestamp is better than a crashed install
fn unix_time_ms() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
} Defensive patterns
Strategy: validation
Validate before calling
fn clock_after_epoch() -> bool {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.is_ok()
}
// gate plugin install/update on a sane clock
if !clock_after_epoch() {
return Err("system clock is before 1970; run NTP sync before installing plugins".into());
} Try / catch
// unix_time_ms panics; isolate plugin installs so one bad clock cannot kill the host process
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
manager.install(source)
}));
match outcome {
Ok(res) => res?,
Err(_) => Err(PluginError::Other("install panicked (check system clock)".into())),
} Prevention
- 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)
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- lsp registry lock poisoned
- mcp registry lock poisoned
- registry lock poisoned
- lane board should serialize
- team registry lock poisoned
AI-assisted analysis of ultraworkers/claw-code@08106b0c37 (2026-08-18).
Data as JSON: /api/errors/f03484c3acbf87fb.
Report an issue: GitHub.