{"record":{"id":"9393f18c017738b0","repo":"gitbutlerapp/gitbutler","slug":"invalid-selector-set-this-cannot-be-empty","errorCode":null,"errorMessage":"Invalid selector set: This cannot be empty","messagePattern":"Invalid selector set: This cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-rebase/src/graph_rebase/mutate.rs","lineNumber":73,"sourceCode":"\n/// A set of some selectors\n#[derive(Debug, Clone)]\npub struct SomeSelectors {\n    selectors: Vec<AnySelector>,\n}\n\nimpl SomeSelectors {\n    /// Creates a set of selectors from different selector input types.\n    ///\n    /// Errors out if the selectors iterator is empty.\n    pub fn new<T>(selectors: impl IntoIterator<Item = T>) -> Result<Self>\n    where\n        T: Into<AnySelector>,\n    {\n        let selectors: Vec<AnySelector> = selectors.into_iter().map(Into::into).collect();\n\n        if selectors.is_empty() {\n            return Err(anyhow!(\"Invalid selector set: This cannot be empty\"));\n        }\n\n        Ok(Self { selectors })\n    }\n\n    /// Returns selectors as a slice.\n    pub fn as_slice(&self) -> &[AnySelector] {\n        &self.selectors\n    }\n}\n\n/// A heterogeneous selector input.\n#[derive(Debug, Clone)]\npub enum AnySelector {\n    /// A selector that already points into the current graph revision.\n    Selector(Selector),\n    /// A commit id that should resolve to a pick step.\n    Commit(gix::ObjectId),","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-rebase/src/graph_rebase/mutate.rs#L55-L91","documentation":"`SomeSelectors::new` builds a `SelectorSet::Some` for graph-rebase editor operations and refuses an empty selector list — an empty `Some` set is meaningless because 'select some' with nothing selected is either a no-op or a typo for `SelectorSet::All`/`None`. The error is a guard against caller mistakes before any graph mutation begins.","triggerScenarios":"Passing an empty Vec to `SomeSelectors::new(...)`, e.g. building `parents_to_disconnect` from a filter that matched nothing, then calling `Editor::disconnect_segment_from` with `SelectorSet::Some(empty)`.","commonSituations":"Calling code that computes selectors dynamically (commits matching a predicate, branches from user selection) and hits an empty result; UI actions invoked with nothing selected.","solutions":["Check the selector list is non-empty before constructing `SomeSelectors`","Decide the intended semantics for 'nothing matched': use `SelectorSet::All` (everything), `SelectorSet::None` (nothing), or early-return from the operation","Trace where the empty list came from — usually an upstream filter or user selection that legitimately produced zero items"],"exampleFix":"// before\nlet selectors = SomeSelectors::new(matching_commits)?; // panics path: Err when empty\n\n// after\nlet set = if matching_commits.is_empty() {\n    SelectorSet::All // or early-return, per intended semantics\n} else {\n    SelectorSet::Some(SomeSelectors::new(matching_commits)?)\n};","handlingStrategy":"validation","validationCode":"let selector_set = if selectors.is_empty() {\n    anyhow::bail!(\"no selectors matched; refusing SelectorSet::Some(empty)\");\n} else {\n    SelectorSet::Some(SomeSelectors::new(selectors)?)\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never construct SomeSelectors from a filter result without checking emptiness","Decide All/None semantics at the call site before building the set","Add a helper `SelectorSet::from_optional(list)` so the empty case is handled in one place"],"tags":["rust","validation","graph-rebase","api-misuse","collections"],"backgroundTag":"empty-collection-argument","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}