{"record":{"id":"240b2b2475adc9c4","repo":"Hmbown/CodeWhale","slug":"cron-field-name-range-start-must-be-end","errorCode":null,"errorMessage":"CRON {field_name} range start must be <= end","messagePattern":"CRON (.+?) range start must be <= end","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/automation_manager.rs","lineNumber":850,"sourceCode":"                let step = step\n                    .trim()\n                    .parse::<u32>()\n                    .with_context(|| format!(\"Failed to parse CRON {field_name} step\"))?;\n                if step == 0 {\n                    bail!(\"CRON {field_name} step must be >= 1\");\n                }\n                (base.trim(), step)\n            } else {\n                (part, 1)\n            };\n\n            let range = if base == \"*\" {\n                (min, max)\n            } else if let Some((start, end)) = base.split_once('-') {\n                let start = parse_cron_atom(start.trim(), min, max, names, field_name)?;\n                let end = parse_cron_atom(end.trim(), min, max, names, field_name)?;\n                if start > end {\n                    bail!(\"CRON {field_name} range start must be <= end\");\n                }\n                (start, end)\n            } else {\n                let start = parse_cron_atom(base, min, max, names, field_name)?;\n                if part.contains('/') {\n                    (start, max)\n                } else {\n                    (start, start)\n                }\n            };\n\n            let mut current = range.0;\n            while current <= range.1 {\n                if !values.contains(&current) {\n                    values.push(current);\n                }\n                let Some(next) = current.checked_add(step) else {\n                    break;","sourceCodeStart":832,"sourceCodeEnd":868,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/automation_manager.rs#L832-L868","documentation":"In a range like '10-5', the start must be less than or equal to the end after both atoms are resolved (including named lookups such as month or weekday names). Descending ranges are not supported, so 'FRI-MON' or '5-1' fails with the field name interpolated.","triggerScenarios":"A field part with '-' whose parsed start exceeds its end, e.g. '0 0 * * 6-1' (Sat-Sun in cron is 6,0 — not 6-1) or '10-5' in minutes.","commonSituations":"Assuming cron ranges wrap around like 'FRI-MON'; writing human-style '20-10' meaning 8pm-10am (needs two ranges); name-to-number confusion where the name resolves higher than expected.","solutions":["Swap the endpoints so start <= end, e.g. '5-10' instead of '10-5'","For wrap-around ranges (e.g. FRI-MON), express as two lists/ranges: '5-6,0-1' or '5,6,0,1'","Check named atom resolution — verify the field's numbering (cron weekday 0=Sunday) matches your intent"],"exampleFix":"// before\n\"0 0 * * 6-1\" // start 6 > end 1\n// after\n\"0 0 * * 0,6\" // Sat and Sun","handlingStrategy":"validation","validationCode":"fn range_ok(start: u32, end: u32) -> bool { start <= end }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Express wrap-around schedules (FRI-MON) as lists: 5,6,0","Remember cron ranges do not wrap across the cycle boundary","Check named atoms resolve in expected order (weekday 0=Sunday)"],"tags":["cron","validation","range"],"backgroundTag":"value-out-of-range","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"}