{"record":{"id":"76780cf165d0abd7","repo":"Hmbown/CodeWhale","slug":"cron-expr-day-of-month-month-combination-can-never","errorCode":null,"errorMessage":"CRON EXPR day-of-month/month combination can never occur","messagePattern":"CRON EXPR day-of-month/month combination can never occur","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/automation_manager.rs","lineNumber":807,"sourceCode":"            day_of_month || weekday\n        }\n    }\n\n    fn validate_date_space(&self) -> Result<()> {\n        if self.day_of_month.is_wildcard {\n            return Ok(());\n        }\n        let months = self.month.values();\n        let days = self.day_of_month.values();\n        let valid = months.iter().copied().any(|month| {\n            let common = days_in_month(2025, month);\n            let leap = days_in_month(2024, month);\n            days.iter().copied().any(|day| day <= common || day <= leap)\n        });\n        if valid {\n            Ok(())\n        } else {\n            bail!(\"CRON EXPR day-of-month/month combination can never occur\")\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct CronField {\n    values: Vec<u32>,\n    is_wildcard: bool,\n}\n\nimpl CronField {\n    fn parse(raw: &str, min: u32, max: u32, names: CronNameMap, field_name: &str) -> Result<Self> {\n        let trimmed = raw.trim();\n        if trimmed.is_empty() {\n            bail!(\"CRON {field_name} field must not be empty\");\n        }\n        let mut values = Vec::new();\n        let is_wildcard = trimmed == \"*\";","sourceCodeStart":789,"sourceCodeEnd":825,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/automation_manager.rs#L789-L825","documentation":"The cron parser validates that a schedule's day-of-month field can actually match at least one day of the given month, including leap years (days_in_month(2024, month) is used as the leap-year upper bound). If every listed day-of-month exceeds the maximum possible length of the specified month(s), the combination can never fire and parsing is rejected. This catches schedules like '0 0 31 2 *' (Feb 31) that would otherwise silently never run.","triggerScenarios":"Calling automation save/validation with a cron expression whose day-of-month entries (e.g. 30, 31) all exceed the number of days in the month(s) given in the month field, e.g. '0 0 31 2 *' or '0 0 30 2,4,6 *' where even leap-year Feb (29) is exceeded.","commonSituations":"Hand-written cron strings copy-pasted from documentation examples ('0 0 31 2 *' is a classic snippet for 'never runs'); assuming cron clamps day 31 to the last day of shorter months as some schedulers do; typo like month 02 with day 30.","solutions":["Change the day-of-month to a value that exists in the specified month(s), e.g. '0 0 29 2 *' for leap-year-only Feb","Widen the month field so the day exists, e.g. '0 0 31 1,3,5,7,8,10,12 *'","Use a step or range that includes at least one valid day, e.g. '0 0 */30 2 *' (30 does not exist in Feb either — use 1-28 instead)"],"exampleFix":"// before\nschedule = \"0 0 31 2 *\"; // never occurs\n// after\nschedule = \"0 0 28 2 *\"; // or 29 for leap-year-only","handlingStrategy":"validation","validationCode":"fn day_valid_for_month(day: u32, month: u32) -> bool {\n    let leap = days_in_month(2024, month);\n    let common = days_in_month(2023, month);\n    day <= leap || day <= common\n}\nassert!(day_valid_for_month(29, 2), \"Feb 29 is the Feb maximum\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check day-of-month against the shortest month in your month list before saving","Remember cron does not clamp day 31 to shorter months","Test every saved schedule with a 'does it ever fire' checker"],"tags":["cron","validation","date"],"backgroundTag":"invalid-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"}