{"record":{"id":"3ae17b57446efa1e","repo":"gitbutlerapp/gitbutler","slug":"invalid-range-s","errorCode":null,"errorMessage":"invalid range: {s}","messagePattern":"invalid range: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-meta/src/virtual_branches_legacy_types.rs","lineNumber":392,"sourceCode":"        /// The index of the first line this hunk is representing.\n        pub start: u32,\n        /// The index of *one past* the last line this hunk is representing.\n        pub end: u32,\n        /// Only set by the frontend when amending\n        pub hunk_header: Option<HunkHeader>,\n    }\n\n    impl FromStr for Hunk {\n        type Err = anyhow::Error;\n\n        fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {\n            let mut range = s.split('-');\n            let start = if let Some(raw_start) = range.next() {\n                raw_start\n                    .parse::<u32>()\n                    .context(format!(\"failed to parse start of range: {s}\"))\n            } else {\n                Err(anyhow!(\"invalid range: {s}\"))\n            }?;\n\n            let end = if let Some(raw_end) = range.next() {\n                raw_end\n                    .parse::<u32>()\n                    .context(format!(\"failed to parse end of range: {s}\"))\n            } else {\n                Err(anyhow!(\"invalid range: {s}\"))\n            }?;\n\n            let hash = if let Some(raw_hash) = range.next() {\n                if raw_hash.is_empty() {\n                    None\n                } else {\n                    let mut buf = [0u8; 16];\n                    hex::decode_to_slice(raw_hash, &mut buf)?;\n                    Some(md5::Digest(buf))\n                }","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-meta/src/virtual_branches_legacy_types.rs#L374-L410","documentation":"Thrown by `Hunk::from_str` (legacy virtual-branches.toml hunk parser) when `s.split('-')` yields no first component while parsing the hunk range start. In practice this arm is unreachable: Rust's `split` always returns at least one item, so a malformed string like \"\" or \"abc\" instead fails with the \"failed to parse start of range: ...\" context error. Seeing this exact message means the defensive else-branch fired, which should be treated as a parser bug rather than bad input. The expected hunk string format is `start-end` optionally followed by a third `-<md5-hex>` segment.","triggerScenarios":"Theoretically only if `s.split('-').next()` returned None, which the stdlib never does. Real-world hunk parse failures on strings like \"\", \"abc\", or \"5\" surface as the sibling parse-context errors or error 641 instead.","commonSituations":"Hand-edited or corrupted legacy `virtual_branches.toml` files; migration tooling that writes hunk lines in an unexpected format; test fixtures with malformed hunk strings.","solutions":["If this exact message appears, report it as a bug in the `Hunk` FromStr implementation (dead defensive branch), since split('-') cannot return an empty iterator","For general hunk parse failures, inspect the offending string in the error message and fix the `start-end[-hash]` format in the source toml","Pre-validate the format before calling `Hunk::from_str` (see exampleFix) so callers get a clearer error","If parsing legacy data wholesale, isolate the failing line and skip/log it instead of aborting the whole workspace load"],"exampleFix":"// before\nlet hunk = Hunk::from_str(input)?; // opaque 'invalid range' / parse errors\n\n// after\nanyhow::ensure!(\n    input.split('-').count() >= 2,\n    \"hunk must be 'start-end[-hash]': {input}\"\n);\nlet hunk = Hunk::from_str(input)?;","handlingStrategy":"validation","validationCode":"fn is_valid_hunk_str(s: &str) -> bool {\n    let mut parts = s.split('-');\n    let (Some(a), Some(b), rest_is_ok) = (parts.next(), parts.next(), true) else {\n        return false;\n    };\n    a.parse::<u32>().is_ok() && b.parse::<u32>().is_ok() && rest_is_ok\n}","typeGuard":null,"tryCatchPattern":"match Hunk::from_str(s) {\n    Ok(h) => { /* ... */ }\n    Err(e) if s.split('-').count() < 2 => log::warn!(\"malformed hunk line (expected start-end): {s} ({e:#})\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Emit hunk lines as `start-end[-hash]` from any tool that writes legacy virtual-branches data","Validate format at load boundaries and quarantine bad lines instead of aborting the workspace","Add round-trip tests (serialize -> parse) for hunk data"],"tags":["rust","parsing","legacy-format","virtual-branches","toml"],"backgroundTag":"string-parse-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}