BloopAI/vibe-kanban · error
validated digest hour
Error message
validated digest hour
What it means
`and_hms_opt` returns an Option and yields None if the given hour/minute/second cannot form a valid NaiveTime (e.g. hour >= 24). The code unwraps it with expect("validated digest hour"), panicking if `run_hour_utc` is not a valid UTC hour (0-23). The panic message is a developer assertion that the digest hour configuration is sane.
Source
Thrown at crates/remote/src/digest/task.rs:144
async fn acquire_run_lock(pool: &PgPool) -> Option<DigestRunLock> {
match DigestRepository::try_acquire_run_lock(pool).await {
Ok(Some(lock)) => Some(lock),
Ok(None) => {
info!("Skipping notification digest cycle because another instance is running it");
None
}
Err(error) => {
error!(error = %error, "Failed to acquire notification digest lock");
None
}
}
}
fn next_run_at(now: DateTime<Utc>, run_hour_utc: u32) -> DateTime<Utc> {
let today = now.date_naive();
let today_run = today
.and_hms_opt(run_hour_utc, 0, 0)
.expect("validated digest hour");
let next_naive = if now.hour() < run_hour_utc {
today_run
} else {
today
.checked_add_days(Days::new(1))
.expect("date overflow for digest schedule")
.and_hms_opt(run_hour_utc, 0, 0)
.expect("validated digest hour")
};
DateTime::from_naive_utc_and_offset(next_naive, Utc)
}
View on GitHub (pinned to 4deb7eca8f)
Solutions
- Validate run_hour_utc <= 23 at config load time (e.g. clamp or return Err from config parsing) before it reaches next_run_at
- Replace expect with and_hms_opt(...).unwrap_or_else(|| now) or propagate an error via Result
- Add a unit test asserting next_run_at panics/errors only for hours > 23 and parses env with range validation
Example fix
// before
let today_run = today.and_hms_opt(run_hour_utc, 0, 0).expect("validated digest hour");
// after
let today_run = today.and_hms_opt(run_hour_utc.min(23), 0, 0)
.ok_or_else(|| anyhow::anyhow!("DIGEST_RUN_HOUR_UTC must be 0-23, got {run_hour_utc}"))?; Defensive patterns
Strategy: validation
Validate before calling
fn validate_run_hour(h: u32) -> Result<u32, String> {
if h <= 23 { Ok(h) } else { Err(format!("run_hour_utc must be 0-23, got {h}")) }
} Type guard
fn is_valid_hour(h: u32) -> bool { h <= 23 } Try / catch
std::panic::catch_unwind(|| next_run_at(now, run_hour_utc)) — or better, convert to Result and use ?
Prevention
- Validate the digest-hour env var at config load, not at scheduling time
- Clamp or reject out-of-range hours with a clear error message
- Add unit tests covering invalid hour values
When it happens
Trigger: `digest_loop` calls `next_run_at(now, run_hour_utc)` with a `run_hour_utc` value of 24 or more (or otherwise unrepresentable), so `today.and_hms_opt(run_hour_utc, 0, 0)` returns None and the expect panics.
Common situations: Misconfigured DIGEST_RUN_HOUR_UTC-style environment variable parsed without range checking; a user setting hour 25 or a negative value cast to u32; a code change introducing a bad default.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- date overflow for digest schedule
- Failed to create tracing filter
- Default profiles v3 JSON is invalid
- request_id called for unsupported request variant
- handled non-session commands earlier
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/760668a9587c5450.
Report an issue: GitHub.