gitbutlerapp/gitbutler · error

Invalid selector set: This cannot be empty

Error message

Invalid selector set: This cannot be empty

What it means

`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.

Source

Thrown at crates/but-rebase/src/graph_rebase/mutate.rs:73

/// A set of some selectors
#[derive(Debug, Clone)]
pub struct SomeSelectors {
    selectors: Vec<AnySelector>,
}

impl SomeSelectors {
    /// Creates a set of selectors from different selector input types.
    ///
    /// Errors out if the selectors iterator is empty.
    pub fn new<T>(selectors: impl IntoIterator<Item = T>) -> Result<Self>
    where
        T: Into<AnySelector>,
    {
        let selectors: Vec<AnySelector> = selectors.into_iter().map(Into::into).collect();

        if selectors.is_empty() {
            return Err(anyhow!("Invalid selector set: This cannot be empty"));
        }

        Ok(Self { selectors })
    }

    /// Returns selectors as a slice.
    pub fn as_slice(&self) -> &[AnySelector] {
        &self.selectors
    }
}

/// A heterogeneous selector input.
#[derive(Debug, Clone)]
pub enum AnySelector {
    /// A selector that already points into the current graph revision.
    Selector(Selector),
    /// A commit id that should resolve to a pick step.
    Commit(gix::ObjectId),

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Check the selector list is non-empty before constructing `SomeSelectors`
  2. Decide the intended semantics for 'nothing matched': use `SelectorSet::All` (everything), `SelectorSet::None` (nothing), or early-return from the operation
  3. Trace where the empty list came from — usually an upstream filter or user selection that legitimately produced zero items

Example fix

// before
let selectors = SomeSelectors::new(matching_commits)?; // panics path: Err when empty

// after
let set = if matching_commits.is_empty() {
    SelectorSet::All // or early-return, per intended semantics
} else {
    SelectorSet::Some(SomeSelectors::new(matching_commits)?)
};
Defensive patterns

Strategy: validation

Validate before calling

let selector_set = if selectors.is_empty() {
    anyhow::bail!("no selectors matched; refusing SelectorSet::Some(empty)");
} else {
    SelectorSet::Some(SomeSelectors::new(selectors)?)
};

Prevention

When it happens

Trigger: 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)`.

Common situations: 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.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/9393f18c017738b0. Report an issue: GitHub.