{"record":{"id":"73f933c4a8b9e56b","repo":"gitbutlerapp/gitbutler","slug":"checked-all-selectors-are-present","errorCode":null,"errorMessage":"checked all selectors are present","messagePattern":"checked all selectors are present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/but-workspace/src/branch/integrate_branch_upstream/plan.rs","lineNumber":268,"sourceCode":"/// before later integration graph mutations can rewire step-graph ancestry.\nfn prepare_squash_step_for_editor<M: RefMetadata>(\n    editor: &Editor<'_, '_, M>,\n    commit_ids: &[gix::ObjectId],\n    message: Option<&str>,\n) -> Result<gix::ObjectId> {\n    if commit_ids.len() < 2 {\n        bail!(\"Squash step must have at least two commits\");\n    }\n\n    let maybe_selectors = commit_ids\n        .iter()\n        .map(|commit_id| editor.try_select_commit(*commit_id))\n        .collect::<Vec<_>>();\n    let ordered_commit_ids = if maybe_selectors.iter().all(Option::is_some) {\n        let ordered_selectors = editor.order_commit_selectors_by_parentage(\n            maybe_selectors\n                .into_iter()\n                .map(|selector| selector.expect(\"checked all selectors are present\"))\n                .collect::<Vec<_>>(),\n        )?;\n        ordered_selectors\n            .iter()\n            .map(|selector| {\n                editor\n                    .find_selectable_commit(*selector)\n                    .map(|(_, commit)| commit.id)\n            })\n            .collect::<Result<Vec<_>>>()?\n    } else {\n        commit_ids.to_vec()\n    };\n\n    let target_commit_id = *ordered_commit_ids\n        .first()\n        .expect(\"validated non-empty squash commit list\");\n    let merge_subject_ids = commit_ids","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/integrate_branch_upstream/plan.rs#L250-L286","documentation":"Panic from `expect(\"checked all selectors are present\")` in squash-step planning (but-workspace integrate_branch_upstream/plan.rs:268). The code maps commit ids to `try_select_commit` options, takes the `all(Option::is_some)` branch, and then unwraps each selector inside `map`. Because the branch is guarded by the `all()` check, every `expect` is provably Some; the assertion just records that coupling.","triggerScenarios":"Planning a squash step whose commit ids are all selectable in the editor; the panic could only fire if the `all()` guard and the later unwrap are separated by an edit (e.g. filtering selectors in between) — not reachable in the shipped code.","commonSituations":"Maintainers refactoring plan.rs (e.g. partial-selector fallback handling); none for end users.","solutions":["No caller-side action","If refactoring, replace option-juggling with `collect::<Option<Vec<_>>>()` so absence propagates as None instead of relying on the paired expect","Add a plan-level test with one unselectable commit to pin the fallback branch"],"exampleFix":"// before\nlet maybe_selectors = commit_ids.iter().map(|id| editor.try_select_commit(*id)).collect::<Vec<_>>();\nlet ordered_commit_ids = if maybe_selectors.iter().all(Option::is_some) {\n    let ordered = editor.order_commit_selectors_by_parentage(\n        maybe_selectors.into_iter().map(|s| s.expect(\"checked all selectors are present\")).collect()\n    )?;\n    ...\n\n// after\nlet maybe_selectors = commit_ids.iter().map(|id| editor.try_select_commit(*id)).collect::<Option<Vec<_>>>();\nlet ordered_commit_ids = if let Some(selectors) = maybe_selectors {\n    let ordered = editor.order_commit_selectors_by_parentage(selectors)?;\n    ...","handlingStrategy":"validation","validationCode":"// If you pre-validate the plan, ensure every squash commit id is selectable:\nlet all_selectable = commit_ids.iter()\n    .all(|id| editor.try_select_commit(*id).is_some());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Unreachable in shipped code; the all(Option::is_some) guard precedes every unwrap","Maintainers: use collect::<Option<Vec<_>>>() when refactoring so absence propagates naturally"],"tags":["rust","panic","expect","option-narrowing","squash-plan","unreachable","gitbutler"],"backgroundTag":"internal-invariant-panic","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}