Hmbown/CodeWhale · error · anyhow::Error

Unsupported RRULE FREQ '{other}'. Supported: ONCE, HOURLY, W

Error message

Unsupported RRULE FREQ '{other}'. Supported: ONCE, HOURLY, WEEKLY, and CRON

What it means

parse_rrule accepts only FREQ values ONCE, HOURLY, WEEKLY, and CRON (case-insensitive). Any other FREQ — the RFC 5545 values DAILY, MONTHLY, YEARLY, MINUTELY, SECONDLY included — is rejected because the scheduler does not implement them.

Source

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

                continue;
            }
            let Some((k, v)) = item.split_once('=') else {
                bail!("Invalid RRULE segment '{item}'");
            };
            parts.insert(k.trim().to_ascii_uppercase(), v.trim().to_string());
        }

        let freq = match parts
            .get("FREQ")
            .map(|value| value.trim().to_ascii_uppercase())
            .as_deref()
        {
            Some("ONCE") => return parse_once_schedule(&parts),
            Some("HOURLY") => AutomationFrequency::Hourly,
            Some("WEEKLY") => AutomationFrequency::Weekly,
            Some("CRON") => return parse_cron_schedule(&parts),
            Some(other) => {
                bail!("Unsupported RRULE FREQ '{other}'. Supported: ONCE, HOURLY, WEEKLY, and CRON")
            }
            None => bail!("RRULE must include FREQ"),
        };

        match freq {
            AutomationFrequency::Hourly => {
                for key in parts.keys() {
                    if key != "FREQ"
                        && key != "INTERVAL"
                        && key != "BYDAY"
                        && key != "BYHOUR"
                        && key != "BYMINUTE"
                    {
                        bail!(
                            "Unsupported RRULE field '{key}' for HOURLY. Allowed: FREQ,INTERVAL,BYDAY,BYHOUR,BYMINUTE"
                        );
                    }
                }

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Express DAILY as `FREQ=HOURLY;INTERVAL=24;BYHOUR=9;BYMINUTE=0` or as `FREQ=CRON;EXPR=0 9 * * *`.
  2. Use `FREQ=CRON;EXPR=...` with a standard 5-field local-time cron for MONTHLY/YEARLY/complex patterns.
  3. Re-read the grammar in the automation tool description (crates/tui/src/tools/automation.rs) before writing the rule.

Example fix

// before
let sched = AutomationSchedule::parse_rrule("FREQ=DAILY;BYHOUR=9")?; // bails: Unsupported FREQ 'DAILY'

// after
let sched = AutomationSchedule::parse_rrule("FREQ=CRON;EXPR=0 9 * * *")?;
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_FREQ: &[&str] = &["ONCE", "HOURLY", "WEEKLY", "CRON"];
let freq = rrule
    .split(';')
    .find_map(|p| p.trim().strip_prefix("FREQ=").or_else(|| p.trim().strip_prefix("freq=")))
    .map(|f| f.trim().to_ascii_uppercase());
if !freq.as_deref().is_some_and(|f| SUPPORTED_FREQ.contains(&f)) {
    anyhow::bail!("use FREQ=ONCE|HOURLY|WEEKLY|CRON; express DAILY via INTERVAL=24 or CRON");
}

Type guard

fn supported_freq(rrule: &str) -> Option<&'static str> {
    let f = rrule.split(';').find(|p| p.trim().to_ascii_uppercase().starts_with("FREQ="))?;
    let v = f.trim()[5..].to_ascii_uppercase();
    match v.as_str() {
        "ONCE" | "HOURLY" | "WEEKLY" | "CRON" => Some(match v.as_str() { "ONCE" => "ONCE", "HOURLY" => "HOURLY", "WEEKLY" => "WEEKLY", _ => "CRON" }),
        _ => None,
    }
}

Try / catch

match AutomationSchedule::parse_rrule(&rrule) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("Unsupported RRULE FREQ") => { /* offer CRON translation */ return Err(e) }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling parse_rrule with `FREQ=DAILY;...`, `FREQ=MONTHLY;...`, or `FREQ=MINUTELY` (even otherwise-valid RFC 5545 rules), or a typo like `FREQ=WEEKLYY` after uppercasing.

Common situations: Porting calendar RRULEs (which commonly use DAILY/MONTHLY) into codewhale automations; assuming full RFC 5545 coverage; copy-paste from iCalendar files.

Related errors


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