{"record":{"id":"12a00d1f2ccd87a4","repo":"BloopAI/vibe-kanban","slug":"date-overflow-for-digest-schedule","errorCode":null,"errorMessage":"date overflow for digest schedule","messagePattern":"date overflow for digest schedule","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/remote/src/digest/task.rs","lineNumber":151,"sourceCode":"        Err(error) => {\n            error!(error = %error, \"Failed to acquire notification digest lock\");\n            None\n        }\n    }\n}\n\nfn next_run_at(now: DateTime<Utc>, run_hour_utc: u32) -> DateTime<Utc> {\n    let today = now.date_naive();\n    let today_run = today\n        .and_hms_opt(run_hour_utc, 0, 0)\n        .expect(\"validated digest hour\");\n\n    let next_naive = if now.hour() < run_hour_utc {\n        today_run\n    } else {\n        today\n            .checked_add_days(Days::new(1))\n            .expect(\"date overflow for digest schedule\")\n            .and_hms_opt(run_hour_utc, 0, 0)\n            .expect(\"validated digest hour\")\n    };\n\n    DateTime::from_naive_utc_and_offset(next_naive, Utc)\n}\n","sourceCodeStart":133,"sourceCodeEnd":158,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/remote/src/digest/task.rs#L133-L158","documentation":"`checked_add_days` returns None when adding the days would overflow the date range (NaiveDate max is ~year 262143). The code expects this never happens, panicking with \"date overflow for digest schedule\" otherwise. It is a guard against scheduling arithmetic at the edge of chrono's representable date range.","triggerScenarios":"`digest_loop` calls `next_run_at` with a `now` (Utc::now()) whose date is near NaiveDate::MAX so adding 1 day overflows and checked_add_days returns None.","commonSituations":"Practically unreachable in normal operation; could appear with a wildly incorrect system clock (year far beyond 262000), clock skew/failure producing sentinel dates, or tests passing synthetic far-future timestamps.","solutions":["Treat as effectively impossible but fail gracefully: replace expect with unwrap_or_else(|| now + chrono::Duration::hours(24))","Use checked arithmetic end-to-end and propagate a Result to digest_loop so a bad clock doesn't crash the process","Log and reset the schedule if system time looks implausible (e.g. year > 9999)"],"exampleFix":"// before\n.checked_add_days(Days::new(1)).expect(\"date overflow for digest schedule\")\n// after\n.checked_add_days(Days::new(1))\n    .unwrap_or_else(|| now.date_naive().succ_opt().unwrap_or(now.date_naive()))","handlingStrategy":"fallback","validationCode":"fn plausible_now(now: DateTime<Utc>) -> bool { now.year() >= 1970 && now.year() < 9999 }","typeGuard":null,"tryCatchPattern":"match std::panic::catch_unwind(|| next_run_at(now, hour)) { Ok(t) => t, Err(_) => now + chrono::Duration::hours(24) }","preventionTips":["Use checked arithmetic throughout and propagate a Result","Sanity-check system clock plausibility before scheduling","Log schedule computation failures instead of panicking in a long-running loop"],"tags":["rust","panic","chrono","date-overflow"],"backgroundTag":"date-overflow","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}