{"record":{"id":"bbf9055d47337b18","repo":"Hmbown/CodeWhale","slug":"unsupported-rrule-field-key-for-weekly-allowe","errorCode":null,"errorMessage":"Unsupported RRULE field '{key}' for WEEKLY. Allowed: FREQ,BYDAY,BYHOUR,BYMINUTE","messagePattern":"Unsupported RRULE field '(.+?)' for WEEKLY\\. Allowed: FREQ,BYDAY,BYHOUR,BYMINUTE","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/automation_manager.rs","lineNumber":366,"sourceCode":"                    .transpose()\n                    .context(\"Failed to parse BYMINUTE\")?;\n                if anchor_hour.is_some_and(|hour| hour > 23) {\n                    bail!(\"BYHOUR must be between 0 and 23\");\n                }\n                if anchor_minute.is_some_and(|minute| minute > 59) {\n                    bail!(\"BYMINUTE must be between 0 and 59\");\n                }\n                Ok(Self::Hourly {\n                    interval_hours,\n                    byday,\n                    anchor_hour,\n                    anchor_minute,\n                })\n            }\n            AutomationFrequency::Weekly => {\n                for key in parts.keys() {\n                    if key != \"FREQ\" && key != \"BYDAY\" && key != \"BYHOUR\" && key != \"BYMINUTE\" {\n                        bail!(\n                            \"Unsupported RRULE field '{key}' for WEEKLY. Allowed: FREQ,BYDAY,BYHOUR,BYMINUTE\"\n                        );\n                    }\n                }\n                let byday_raw = parts\n                    .get(\"BYDAY\")\n                    .ok_or_else(|| anyhow::anyhow!(\"WEEKLY schedules require BYDAY\"))?;\n                let byday = parse_byday(&byday_raw.to_ascii_uppercase())?;\n                if byday.is_empty() {\n                    bail!(\"BYDAY cannot be empty for WEEKLY schedules\");\n                }\n                let byhour = parts\n                    .get(\"BYHOUR\")\n                    .ok_or_else(|| anyhow::anyhow!(\"WEEKLY schedules require BYHOUR\"))?\n                    .parse::<u32>()\n                    .context(\"Failed to parse BYHOUR\")?;\n                let byminute = parts\n                    .get(\"BYMINUTE\")","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/automation_manager.rs#L348-L384","documentation":"For FREQ=WEEKLY the parser whitelists exactly FREQ, BYDAY, BYHOUR, BYMINUTE — INTERVAL is deliberately not allowed because WEEKLY fires on the named weekdays at the fixed BYHOUR:BYMINUTE local time. Any other key (INTERVAL, UNTIL, COUNT, EXPR, ...) is rejected rather than ignored.","triggerScenarios":"parse_rrule(\"FREQ=WEEKLY;INTERVAL=2;BYDAY=MO;BYHOUR=9;BYMINUTE=0\") (fortnightly via INTERVAL), or `FREQ=WEEKLY;COUNT=4;...`.","commonSituations":"Copying an RFC 5545 biweekly rule (`FREQ=WEEKLY;INTERVAL=2`) from a calendar system; trying to bound or offset a weekly schedule with standard RRULE parts.","solutions":["For plain weekly schedules, drop INTERVAL: `FREQ=WEEKLY;BYDAY=MO,WE;BYHOUR=9;BYMINUTE=30`.","For biweekly/fortnightly, use `FREQ=CRON;EXPR=30 9 * * 1` style only if weekly cadence matches, or schedule two rules on alternating weeks in your own driver.","Check each key against FREQ,BYDAY,BYHOUR,BYMINUTE before submitting."],"exampleFix":"// before\nlet s = AutomationSchedule::parse_rrule(\"FREQ=WEEKLY;INTERVAL=2;BYDAY=MO;BYHOUR=9;BYMINUTE=0\")?; // bails on INTERVAL\n\n// after\nlet s = AutomationSchedule::parse_rrule(\"FREQ=WEEKLY;BYDAY=MO;BYHOUR=9;BYMINUTE=0\")?;","handlingStrategy":"validation","validationCode":"const WEEKLY_ALLOWED: &[&str] = &[\"FREQ\", \"BYDAY\", \"BYHOUR\", \"BYMINUTE\"];\nfor (k, _) in rrule.split(';').filter_map(|p| p.trim().split_once('=')) {\n    if !WEEKLY_ALLOWED.contains(&k.trim().to_ascii_uppercase().as_str()) {\n        anyhow::bail!(\"{} is not allowed for FREQ=WEEKLY (no INTERVAL)\", k);\n    }\n}","typeGuard":"fn weekly_keys_allowed(rrule: &str) -> bool {\n    rrule.split(';').filter_map(|p| p.trim().split_once('=')).all(|(k, _)| {\n        [\"FREQ\", \"BYDAY\", \"BYHOUR\", \"BYMINUTE\"].contains(&k.trim().to_ascii_uppercase().as_str())\n    })\n}","tryCatchPattern":"match AutomationSchedule::parse_rrule(&rrule) {\n    Ok(s) => s,\n    Err(e) if e.to_string().contains(\"for WEEKLY\") => { /* drop INTERVAL/UNTIL/COUNT or switch to CRON */ return Err(e) }\n    Err(e) => return Err(e),\n}","preventionTips":["Remember WEEKLY has no INTERVAL — it fires every matching weekday at BYHOUR:BYMINUTE.","Do not paste raw iCalendar RRULEs; strip or translate unsupported parts.","Express fortnightly patterns with two rules or a cron-driven driver."],"tags":["rrule","automation","schedule","unsupported-field"],"backgroundTag":"rrule-unsupported-field","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}