{"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":829,"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":811,"sourceCodeEnd":847,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/automation_manager.rs#L811-L847","documentation":"Within a comma-separated cron field, empty list items are invalid: each part between commas must contain a value. The parser splits on ',' and bails when any resulting part trims to empty, e.g. '1,,5' or a trailing comma '1,5,'.","triggerScenarios":"A cron field like 'minutes=1,,5', '*/5, ' or '0,15,30,' — any double comma, leading, or trailing comma in minute/hour/day/month/weekday.","commonSituations":"Programmatic list building joined with commas where a list element was empty (e.g. vec of Option values stringified); hand-editing a schedule and deleting a value but not its comma.","solutions":["Remove the extra/stray comma so every item has a value, e.g. '1,5' instead of '1,,5'","Build the field by filtering empty entries before joining: parts.iter().filter(|p| !p.is_empty()).join(\",\")","Trim the whole field and strip trailing commas before saving"],"exampleFix":"// before\nlet field = format!(\"{},,{}\", a, b); // empty item\n// after\nlet field = [a, b].iter().filter(|v| !v.is_empty()).cloned().collect::<Vec<_>>().join(\",\");","handlingStrategy":"validation","validationCode":"fn no_empty_list_items(field: &str) -> bool {\n    field.split(',').all(|p| !p.trim().is_empty())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter empty entries before joining list values with commas","Never hand-edit fields by deleting only the value","Round-trip parse fields before persisting them"],"tags":["cron","validation","format"],"backgroundTag":"invalid-argument-format","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"}