{"record":{"id":"6e417c4a56071dbc","repo":"zed-industries/zed","slug":"only-one-split-can-use-rest","errorCode":null,"errorMessage":"only one split can use 'rest'","messagePattern":"only one split can use 'rest'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/edit_prediction_cli/src/split_dataset.rs","lineNumber":187,"sourceCode":"fn compute_split_counts(specs: &[SplitSpec], total: usize) -> Result<Vec<usize>> {\n    let mut counts = vec![0usize; specs.len()];\n    let mut remaining = total;\n    let mut rest_index: Option<usize> = None;\n\n    for (i, spec) in specs.iter().enumerate() {\n        match &spec.size {\n            SplitSize::Percentage(pct) => {\n                let count = (total as f64 * pct).round() as usize;\n                counts[i] = count.min(remaining);\n                remaining = remaining.saturating_sub(counts[i]);\n            }\n            SplitSize::Absolute(count) => {\n                counts[i] = (*count).min(remaining);\n                remaining = remaining.saturating_sub(counts[i]);\n            }\n            SplitSize::Rest => {\n                if rest_index.is_some() {\n                    bail!(\"only one split can use 'rest'\");\n                }\n                rest_index = Some(i);\n            }\n        }\n    }\n\n    if let Some(idx) = rest_index {\n        counts[idx] = remaining;\n    }\n\n    Ok(counts)\n}\n\nfn write_lines_to_file(path: &Path, lines: &[String]) -> Result<()> {\n    if let Some(parent) = path.parent() {\n        if !parent.as_os_str().is_empty() {\n            std::fs::create_dir_all(parent)\n                .with_context(|| format!(\"failed to create directory '{}'\", parent.display()))?;","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/edit_prediction_cli/src/split_dataset.rs#L169-L205","documentation":"Bailed while computing split sizes for `ep split`: more than one split spec used the `=rest` size. `rest` means 'whatever remains after all other splits are satisfied', which is only well-defined for a single split, so a second occurrence is rejected before any lines are distributed.","triggerScenarios":"Running `ep split data.jsonl train.jsonl=80% valid.jsonl=rest test.jsonl=rest` — two specs claiming the remainder.","commonSituations":"Copy-pasting a `=rest` spec when adding an extra split; adapting a two-way split template to three-way without converting one rest to an explicit size.","solutions":["Give all but one split an explicit percentage or absolute count","Keep `=rest` on the single split that should absorb leftovers"],"exampleFix":"# before\nep split data.jsonl train.jsonl=80% dev.jsonl=rest test.jsonl=rest\n\n# after\nep split data.jsonl train.jsonl=80% dev.jsonl=10% test.jsonl=rest","handlingStrategy":"validation","validationCode":"let rest_count = specs.iter().filter(|s| s.ends_with(\"=rest\")).count();\nif rest_count > 1 {\n    // reject before running: only one split may claim the remainder\n}","typeGuard":null,"tryCatchPattern":"Count `=rest` occurrences across the spec list up front and fail with a clear message naming the duplicate splits.","preventionTips":["Audit spec lists for duplicate rest before launching split","Convert extra rest specs to explicit percentages or counts when adding splits","Encode the invariant 'at most one rest' in whatever generates the command line"],"tags":["cli","conflicting-options","dataset-splitting","rust"],"backgroundTag":"conflicting-cli-options","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}