{"record":{"id":"aa1fdf1beeda8540","repo":"nikivdev/code","slug":"failed-to-calculate-next-day","errorCode":null,"errorMessage":"failed to calculate next day","messagePattern":"failed to calculate next day","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/ssh_keys.rs","lineNumber":518,"sourceCode":"    let path = ssh_unlock_path()?;\n    let entry = SshKeyUnlock {\n        expires_at: expires_at.timestamp(),\n    };\n    let content = serde_json::to_string_pretty(&entry)?;\n    fs::write(&path, content)?;\n    Ok(())\n}\n\nfn unlock_expires_at(entry: &SshKeyUnlock) -> Option<DateTime<Utc>> {\n    DateTime::<Utc>::from_timestamp(entry.expires_at, 0)\n}\n\nfn next_local_midnight_utc() -> Result<DateTime<Utc>> {\n    let now = Local::now();\n    let tomorrow = now\n        .date_naive()\n        .succ_opt()\n        .ok_or_else(|| anyhow::anyhow!(\"failed to calculate next day\"))?;\n    let naive = tomorrow\n        .and_hms_opt(0, 0, 0)\n        .ok_or_else(|| anyhow::anyhow!(\"failed to build midnight time\"))?;\n    let local_dt = Local\n        .from_local_datetime(&naive)\n        .single()\n        .or_else(|| Local.from_local_datetime(&naive).earliest())\n        .ok_or_else(|| anyhow::anyhow!(\"failed to resolve local midnight\"))?;\n    Ok(local_dt.with_timezone(&Utc))\n}\n\nfn prompt_touch_id() -> Result<()> {\n    if !cfg!(target_os = \"macos\") {\n        bail!(\"Touch ID is not available on this OS\");\n    }\n    if std::env::var(\"FLOW_NO_TOUCH_ID\").is_ok() || !std::io::stdin().is_terminal() {\n        bail!(\"Touch ID prompt requires an interactive terminal\");\n    }","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/ssh_keys.rs#L500-L536","documentation":"next_local_midnight_utc computes tomorrow's date via chrono's NaiveDate::succ_opt, which returns None only when advancing the date overflows the date range representable by chrono. The function throws this anyhow error when succ_opt fails so the caller (unlock_ssh_key, which sets an expiry at next local midnight) cannot compute a valid unlock deadline.","triggerScenarios":"Calling next_local_midnight_utc (via unlock_ssh_key) when the current local date is at or near chrono's NaiveDate maximum boundary (year ~262143), so succ_opt() returns None.","commonSituations":"Extremely rare in practice; only seen with a corrupted system clock set to a far-future date, or running in an environment whose clock is misconfigured to chrono's max date.","solutions":["Check the system clock (date / timedatectl) and correct it to the current real date","Add a fallback that treats succ_opt() == None as 'use now + 1 day' via checked arithmetic and a hard error only if that also fails","Pin/upgrade chrono to ensure date arithmetic behavior is as expected"],"exampleFix":"// before\n.ok_or_else(|| anyhow::anyhow!(\"failed to calculate next day\"))?\n// after\nlet tomorrow = now.date_naive().succ_opt().unwrap_or_else(|| now.date_naive() + chrono::Duration::days(1));","handlingStrategy":"validation","validationCode":"let today = chrono::Local::now().date_naive();\nif today.succ_opt().is_none() {\n    eprintln!(\"system date is out of range; fix the clock before unlocking\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"match unlock_ssh_key() {\n    Ok(expiry) => println!(\"key unlocks until {}\", expiry),\n    Err(e) if e.to_string().contains(\"failed to calculate next day\") => fix_system_clock(),\n    Err(e) => eprintln!(\"unlock failed: {}\", e),\n}","preventionTips":["Keep the system clock synchronized (NTP enabled)","Treat any date-related error at unlock time as a clock misconfiguration symptom","Prefer checked date arithmetic with sane fallbacks over hard errors"],"tags":["chrono","datetime","date-arithmetic"],"backgroundTag":"date-calculation-failed","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}