Hmbown/CodeWhale · error
ONCE schedules require AT
Error message
ONCE schedules require AT
What it means
AutomationSchedule::parse_rrule treats FREQ=ONCE as a one-shot: only FREQ and AT are allowed, and the AT key is mandatory because a one-shot without a fire time is meaningless. A missing AT is rejected with this error at parse time, before the automation is stored.
Source
Thrown at crates/tui/src/automation_manager.rs:602
"SU" => Weekday::Sun,
other => bail!("Invalid BYDAY value '{other}'"),
};
if !days.contains(&day) {
days.push(day);
}
}
Ok(days)
}
fn parse_once_schedule(parts: &BTreeMap<String, String>) -> Result<AutomationSchedule> {
for key in parts.keys() {
if key != "FREQ" && key != "AT" {
bail!("Unsupported RRULE field '{key}' for ONCE. Allowed: FREQ,AT");
}
}
let raw_at = parts
.get("AT")
.ok_or_else(|| anyhow::anyhow!("ONCE schedules require AT"))?;
let at = parse_once_at(raw_at)?;
Ok(AutomationSchedule::Once { at })
}
fn parse_cron_schedule(parts: &BTreeMap<String, String>) -> Result<AutomationSchedule> {
for key in parts.keys() {
if key != "FREQ" && key != "EXPR" {
bail!("Unsupported RRULE field '{key}' for CRON. Allowed: FREQ,EXPR");
}
}
let expr = parts
.get("EXPR")
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.ok_or_else(|| anyhow::anyhow!("CRON schedules require EXPR"))?;
ParsedCronExpr::parse(&expr)?;
Ok(AutomationSchedule::Cron { expr })
}View on GitHub (pinned to 8880682c63)
Solutions
- Append AT with a local or RFC3339 time: FREQ=ONCE;AT=2026-08-03T14:30 or FREQ=ONCE;AT=2026-08-03T12:30:00Z
- Use exactly the key AT and no other fields (only FREQ and AT are allowed for ONCE)
- Validate with parse_rrule before persisting
Example fix
// before let rrule = "FREQ=ONCE"; // after let rrule = "FREQ=ONCE;AT=2026-08-03T14:30";
Defensive patterns
Strategy: validation
Validate before calling
let parts: std::collections::BTreeMap<&str, &str> = rrule
.split(';')
.filter_map(|kv| kv.split_once('='))
.collect();
if parts.get("FREQ").copied() == Some("ONCE") {
let at = parts.get("AT").context("ONCE schedules require AT=YYYY-MM-DDTHH:MM[:SS] or RFC3339")?;
ensure!(!at.trim().is_empty(), "AT must not be empty");
} Type guard
fn is_valid_once_rrule(rrule: &str) -> bool {
let parts: std::collections::BTreeMap<&str, &str> = rrule
.split(';')
.filter_map(|kv| kv.split_once('='))
.collect();
parts.get("FREQ").copied() == Some("ONCE")
&& parts.get("AT").is_some_and(|at| !at.trim().is_empty())
&& parts.keys().all(|k| matches!(*k, "FREQ" | "AT"))
} Prevention
- Emit ONCE schedules from a template that always includes AT
- Accept only 'YYYY-MM-DDTHH:MM[:SS]' local or RFC3339 AT values; anything else fails in parse_once_at with a usage hint
- Run parse_rrule on user- or model-supplied RRULEs before persisting
When it happens
Trigger: Creating/updating an automation with rrule 'FREQ=ONCE' (no ';AT=...'), or with the field misspelled so the parser sees no AT key. AT accepts local 'YYYY-MM-DDTHH:MM[:SS]' or RFC3339.
Common situations: Authors copying the ONCE template but deleting the AT clause; model-generated schedules omitting the timestamp; field-name typos like 'AT ' or 'AT=' (empty value fails later in parse_once_at instead).
Related errors
- WEEKLY schedules require BYDAY
- WEEKLY schedules require BYHOUR
- WEEKLY schedules require BYMINUTE
- CRON schedules require EXPR
- Unable to construct HOURLY anchor
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/8825f993391f9d1c.
Report an issue: GitHub.