Y2Z/monolith · error

Time went backwards

Error message

Time went backwards

What it means

This panic comes from an `.expect()` on `SystemTime::now().duration_since(UNIX_EPOCH)` inside `is_expired` in src/cookies.rs. `duration_since` returns `Err` if the system clock is set before the Unix epoch (1970-01-01), so the library panics instead of guessing an expiry. It means the OS clock is wrong, not that the cookie or session is invalid.

Source

Thrown at src/cookies.rs:29

    pub name: String,
    pub value: String,
}

#[derive(Debug)]
pub enum CookieFileContentsParseError {
    InvalidHeader,
}

impl Cookie {
    pub fn is_expired(&self) -> bool {
        if self.expires == 0 {
            return false; // Session, never expires
        }

        let start = SystemTime::now();
        let since_the_epoch = start
            .duration_since(UNIX_EPOCH)
            .expect("Time went backwards");

        self.expires < since_the_epoch.as_secs()
    }

    pub fn matches_url(&self, url: &str) -> bool {
        match Url::parse(url) {
            Ok(url) => {
                // Check protocol scheme
                match url.scheme() {
                    "http" => {
                        if self.https_only {
                            return false;
                        }
                    }
                    "https" => {}
                    _ => {
                        // Should never match URLs of protocols other than HTTP(S)
                        return false;

View on GitHub (pinned to a6fc8d0095)

Solutions

  1. Fix the system clock: enable NTP or systemd-timesyncd so the time is after 1970.
  2. Check container/VM time sync: ensure the host clock is correct and RTC/hwclock is set before running the app.
  3. Patch or wrap `is_expired` to treat `duration_since` failure as 'not expired' (return false) instead of panicking.
  4. File an upstream issue so the library replaces `.expect()` with graceful handling of pre-epoch clocks.

Example fix

// before
let since_the_epoch = start
    .duration_since(UNIX_EPOCH)
    .expect("Time went backwards");
// after
let since_the_epoch = start
    .duration_since(UNIX_EPOCH)
    .unwrap_or_default(); // pre-epoch clock: treat as t=0 (nothing expired)
Defensive patterns

Strategy: validation

Validate before calling

fn system_clock_is_sane() -> bool {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_secs() > 1_600_000_000) // roughly after Sep 2020
        .unwrap_or(false)
}
// call before request handling; if false, resync clock via NTP

Prevention

When it happens

Trigger: Calling `is_expired` (directly or via cookie/session checks during request handling) while the system clock is set earlier than 1970-01-01T00:00:00Z, so `duration_since(UNIX_EPOCH)` yields `Err(SystemTimeError)`.

Common situations: Containers/VMs with no RTC whose clock starts at or before the epoch, bare-metal devices booting with a reset CMOS battery, embedded systems without NTP sync, clock drift after restore from a snapshot.

Related errors


AI-assisted analysis of Y2Z/monolith@a6fc8d0095 (2026-09-05). Data as JSON: /api/errors/c85c11b26524fe8a. Report an issue: GitHub.