gitbutlerapp/gitbutler · error

Expected selector for

Error message

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

What it means

ToReferenceSelector::to_reference_selector normalizes a Selector and asserts the graph node is a Step::Reference (a named ref such as a branch). If it resolves to any other step kind (e.g. a Pick/commit), the conversion is invalid and the library bails.

Solutions

  1. Verify editor.graph[selector.id] is a Step::Reference before the call
  2. Use to_commit_selector if the selector targets a commit
  3. Re-derive the selector from the current editor/graph state

Example fix

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

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Calling to_reference_selector with a Selector that normalizes to a non-Reference step — e.g. passing a commit-pick selector into a move-branch/rename-reference API, or a stale selector that re-resolves to a Pick after graph edits.

Common situations: Confusing commit selectors with branch selectors when scripting rebase graph mutations; calling branch operations on commit ids; selectors invalidated by earlier mutations to the editor graph.

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/5cc103df3d7c8733. Report an issue: GitHub.

Appendix: source

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

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)
    }
}

impl ToSelector for Selector {
    fn to_selector(&self, _: &Editor<impl RefMetadata>) -> Result<Selector> {
        Ok(*self)
    }
}

/// Represents places where `safe_checkout` should be called from
#[derive(Debug, Clone)]
pub(crate) enum Checkout {
    /// The HEAD of the `repo` the editor was created for.
    Head {
        selector: Selector,

View on GitHub (pinned to 58e5313667)