{"record":{"id":"b0f206273bd0e04a","repo":"Hmbown/CodeWhale","slug":"cron-field-name-field-contains-an-empty-list-ite","errorCode":null,"errorMessage":"CRON {field_name} field contains an empty list item","messagePattern":"CRON (.+?) field contains an empty list item","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/automation_manager.rs","lineNumber":730,"sourceCode":"\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 == \"*\";\n        for part in trimmed.split(',') {\n            let part = part.trim();\n            if part.is_empty() {\n                bail!(\"CRON {field_name} field contains an empty list item\");\n            }\n            let (base, step) = if let Some((base, step)) = part.split_once('/') {\n                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)?;","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/automation_manager.rs#L712-L748","documentation":"A comma-separated cron field contained an empty list item: each part is trimmed and checked for emptiness before range/step parsing. '1,,3', a trailing comma '1,2,', or a leading ',1' in any of the five fields triggers it.","triggerScenarios":"EXPR='0 0 12 1,,3 *'; EXPR='0 9-17 * * 1,'; templated lists where a filter removed an element and left an empty slot between commas.","commonSituations":"Programmatically built comma lists with a trailing comma; join of an array that contains empty strings; simple typos.","solutions":["Remove empty items: '1,3' not '1,,3'","Strip trailing/leading commas before submitting","When generating lists, filter out empty strings before joining with ','","Dry-run the full EXPR via parse_rrule"],"exampleFix":"// before\nrrule = \"FREQ=CRON;EXPR=0 0 12 1,,3 *\"\n\n// after\nrrule = \"FREQ=CRON;EXPR=0 0 12 1,3 *\"","handlingStrategy":"validation","validationCode":"fn cron_list_items_nonempty(expr: &str) -> bool {\n    expr.split_whitespace()\n        .all(|field| field.split(',').all(|item| !item.trim().is_empty()))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Join only non-empty tokens when generating comma lists","Reject double commas and leading/trailing commas at the form layer","Validate the full EXPR with parse_rrule before persisting","Trim user input around commas, then re-check for empties"],"tags":["rust","cron","validation","syntax"],"backgroundTag":"cron-invalid-field-syntax","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}