Hmbown/CodeWhale · error · anyhow::Error

INTERVAL must be >= 1 for HOURLY schedules

Error message

INTERVAL must be >= 1 for HOURLY schedules

What it means

INTERVAL for HOURLY schedules parses as u32 and must be at least 1, because it is the number of hours between runs; 0 would mean an infinite loop of identical fire times. A missing INTERVAL defaults to 1, so only an explicit INTERVAL=0 reaches this check (negatives fail earlier as a u32 parse error under 'Failed to parse INTERVAL').

Source

Thrown at crates/tui/src/automation_manager.rs:334

                    if key != "FREQ"
                        && key != "INTERVAL"
                        && key != "BYDAY"
                        && key != "BYHOUR"
                        && key != "BYMINUTE"
                    {
                        bail!(
                            "Unsupported RRULE field '{key}' for HOURLY. Allowed: FREQ,INTERVAL,BYDAY,BYHOUR,BYMINUTE"
                        );
                    }
                }
                let interval_hours = parts
                    .get("INTERVAL")
                    .map(|v| v.parse::<u32>())
                    .transpose()
                    .context("Failed to parse INTERVAL")?
                    .unwrap_or(1);
                if interval_hours == 0 {
                    bail!("INTERVAL must be >= 1 for HOURLY schedules");
                }
                let byday = parts
                    .get("BYDAY")
                    .map(|value| parse_byday(&value.to_ascii_uppercase()))
                    .transpose()?;
                let anchor_hour = parts
                    .get("BYHOUR")
                    .map(|value| value.parse::<u32>())
                    .transpose()
                    .context("Failed to parse BYHOUR")?;
                let anchor_minute = parts
                    .get("BYMINUTE")
                    .map(|value| value.parse::<u32>())
                    .transpose()
                    .context("Failed to parse BYMINUTE")?;
                if anchor_hour.is_some_and(|hour| hour > 23) {
                    bail!("BYHOUR must be between 0 and 23");
                }

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Set INTERVAL to the real spacing in hours, minimum 1 (`FREQ=HOURLY;INTERVAL=1` for hourly).
  2. If sub-hourly firing was intended, use `FREQ=CRON;EXPR=...` (e.g. `*/15 * * * *`).
  3. Clamp/validate computed intervals to >= 1 before building the RRULE string.

Example fix

// before
let rrule = format!("FREQ=HOURLY;INTERVAL={interval}"); // interval == 0 -> bails

// after
let interval = interval.max(1);
let rrule = format!("FREQ=HOURLY;INTERVAL={interval}");
Defensive patterns

Strategy: validation

Validate before calling

let interval: u32 = interval_input.max(1); // clamp before formatting
let rrule = format!("FREQ=HOURLY;INTERVAL={interval}");

Type guard

fn valid_hourly_interval(v: u32) -> bool { v >= 1 }

Try / catch

match AutomationSchedule::parse_rrule(&rrule) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("INTERVAL must be >= 1") => AutomationSchedule::parse_rrule("FREQ=HOURLY;INTERVAL=1")?,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: parse_rrule("FREQ=HOURLY;INTERVAL=0") or `INTERVAL=00` (both parse to 0).

Common situations: Computing INTERVAL from a variable that can be zero (e.g. `hours = user_input`); config templates defaulting empty numeric fields to 0.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/d1d5137c0eeecfd2. Report an issue: GitHub.