{"record":{"id":"27acee85a982526e","repo":"Hmbown/CodeWhale","slug":"unsupported-rrule-field-key-for-hourly-allowe","errorCode":null,"errorMessage":"Unsupported RRULE field '{key}' for HOURLY. Allowed: FREQ,INTERVAL,BYDAY,BYHOUR,BYMINUTE","messagePattern":"Unsupported RRULE field '(.+?)' for HOURLY\\. Allowed: FREQ,INTERVAL,BYDAY,BYHOUR,BYMINUTE","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/automation_manager.rs","lineNumber":377,"sourceCode":"            Some(\"HOURLY\") => AutomationFrequency::Hourly,\n            Some(\"WEEKLY\") => AutomationFrequency::Weekly,\n            Some(\"CRON\") => return parse_cron_schedule(&parts),\n            Some(other) => {\n                bail!(\"Unsupported RRULE FREQ '{other}'. Supported: ONCE, HOURLY, WEEKLY, and CRON\")\n            }\n            None => bail!(\"RRULE must include FREQ\"),\n        };\n\n        match freq {\n            AutomationFrequency::Hourly => {\n                for key in parts.keys() {\n                    if key != \"FREQ\"\n                        && key != \"INTERVAL\"\n                        && key != \"BYDAY\"\n                        && key != \"BYHOUR\"\n                        && key != \"BYMINUTE\"\n                    {\n                        bail!(\n                            \"Unsupported RRULE field '{key}' for HOURLY. Allowed: FREQ,INTERVAL,BYDAY,BYHOUR,BYMINUTE\"\n                        );\n                    }\n                }\n                let interval_hours = parts\n                    .get(\"INTERVAL\")\n                    .map(|v| v.parse::<u32>())\n                    .transpose()\n                    .context(\"Failed to parse INTERVAL\")?\n                    .unwrap_or(1);\n                if interval_hours == 0 {\n                    bail!(\"INTERVAL must be >= 1 for HOURLY schedules\");\n                }\n                let byday = parts\n                    .get(\"BYDAY\")\n                    .map(|value| parse_byday(&value.to_ascii_uppercase()))\n                    .transpose()?;\n                let anchor_hour = parts","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/automation_manager.rs#L359-L395","documentation":"For FREQ=HOURLY, the parser whitelists only FREQ, INTERVAL, BYDAY, BYHOUR, and BYMINUTE. Any other RRULE key (e.g. BYDAYSET, COUNT, UNTIL, BYMONTH) makes it reject the rule rather than silently ignore it. This keeps hourly schedules deterministic and free of unsupported semantics.","triggerScenarios":"Parsing 'RRULE:FREQ=HOURLY;COUNT=5' or 'RRULE:FREQ=HOURLY;INTERVAL=2;BYMONTH=3' — any key outside the whitelist triggers the error.","commonSituations":"Pasting a full RFC-5545 RRULE from a calendar app that includes COUNT/UNTIL/WKST; typos like BYHOURS or INTERVALS.","solutions":["Remove the unsupported key from the RRULE string","Replace COUNT/UNTIL-based limits with the automation tool's own end conditions","Fix typos so keys are exactly FREQ, INTERVAL, BYDAY, BYHOUR, or BYMINUTE (uppercase)"],"exampleFix":"// before\nRRULE:FREQ=HOURLY;INTERVAL=2;COUNT=10\n// after\nRRULE:FREQ=HOURLY;INTERVAL=2","handlingStrategy":"validation","validationCode":"const ALLOWED = [\"FREQ\",\"INTERVAL\",\"BYDAY\",\"BYHOUR\",\"BYMINUTE\"];\nfor (const kv of rule.split(';').slice(1)) {\n  const key = kv.split('=')[0].trim().toUpperCase();\n  if (!ALLOWED.includes(key)) throw new Error(`Unsupported RRULE field ${key} for HOURLY`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  parse_rrule(rule)?;\n} catch e if e.to_string().contains(\"Unsupported RRULE field\") {\n  eprintln!(\"{e}: strip unknown keys or use CRON for richer schedules\");\n}","preventionTips":["Strip COUNT/UNTIL/WKST when importing rules from calendar apps","Whitelist keys at the config-writing boundary","Document the supported key set next to the schedule editor"],"tags":["rrule","scheduling","validation"],"backgroundTag":"unsupported-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}