gitbutlerapp/gitbutler · error

Expected selector for

Error message

Expected selector for {step:?} to refer to a commit

What it means

ToCommitSelector::to_commit_selector normalizes a Selector against the editor's history and asserts that the graph node it points to is a Step::Pick (a commit). If the normalized selector resolves to any other step kind (e.g. a Step::Reference), the requested conversion is impossible and the library bails.

Solutions

  1. Confirm the selector points at a Pick step before calling to_commit_selector (inspect editor.graph[selector.id])
  2. Use to_reference_selector instead if the selector names a reference
  3. Re-obtain the selector from the current editor state after graph mutations

Example fix

// before: selector names a branch -> error
let commit = selector.to_commit_selector(&editor)?;
// after
let step = &editor.graph[selector.id];
let commit = match step {
    Step::Pick(_) => selector.to_commit_selector(&editor)?,
    Step::Reference { .. } => bail!("use a commit selector here"),
    _ => bail!("unsupported step"),
};
Defensive patterns

Strategy: type-guard

Validate before calling

let step = &editor.graph[selector.id];
if !matches!(step, Step::Pick(_)) { return Err(anyhow!("not a commit selector")); }

Type guard

fn is_pick(selector: Selector, editor: &Editor<impl RefMetadata>) -> bool {
    matches!(editor.graph[selector.id], Step::Pick(_))
}

Try / catch

match selector.to_commit_selector(&editor) {
    Ok(commit) => commit,
    Err(_) => bail!("selector does not refer to a commit; check step kind first"),
}

Prevention

When it happens

Trigger: Passing a Selector that resolves to a reference/other non-pick step into any API taking impl ToCommitSelector — e.g. calling to_commit_selector on a selector obtained for a branch/reference step, or an id that after normalize_selector lands on a non-Pick node.

Common situations: Mixing up selectors for references and commits when scripting graph edits (move_branch vs commit operations); using a stale selector index after the graph was mutated so normalization resolves elsewhere.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/9f15d931128dd5f9. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-rebase/src/graph_rebase/mod.rs:221

///
/// Hash, PartialEq, and Eq are implemented for this struct. Because selectors
/// are a pointer to a node in a particular version of the Editor's internal
/// representation, it means that you can have two selectors that when
/// normalised point to the same node. If you want to ensure you have just one
/// selector to a given node, make sure you are working with selectors all
/// normalised to the latest revision of the Editor.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Selector {
    id: StepGraphIndex,
    revision: usize,
}

impl ToCommitSelector for Selector {
    fn to_commit_selector(&self, editor: &Editor<impl RefMetadata>) -> Result<Selector> {
        let selector = editor.history.normalize_selector(*self)?;
        let step = &editor.graph[selector.id];
        if !matches!(step, Step::Pick(_)) {
            bail!("Expected selector for {step:?} to refer to a commit");
        }

        Ok(selector)
    }
}

impl ToReferenceSelector for Selector {
    fn to_reference_selector(&self, editor: &Editor<impl RefMetadata>) -> Result<Selector> {
        let selector = editor.history.normalize_selector(*self)?;
        let step = &editor.graph[selector.id];
        if !matches!(step, Step::Reference { .. }) {
            bail!("Expected selector for {step:?} to refer to a reference");
        }

        Ok(selector)
    }
}

View on GitHub (pinned to 58e5313667)