gitbutlerapp/gitbutler · error

Expected selector to point to a pick

Error message

Expected selector to point to a pick

What it means

LookupStep::lookup_pick resolves a Selector to its graph step and asserts it is a Step::Pick, returning the commit id. Any other step kind (e.g. a Reference) makes the request invalid, so the library bails instead of returning a wrong id.

Solutions

  1. Check the step kind via lookup_step before calling lookup_pick
  2. Use lookup_reference for reference selectors
  3. Re-create/re-normalize the selector against the current editor state

Example fix

// before
let id = editor.lookup_pick(selector)?; // selector is a reference
// after
let id = match editor.lookup_step(selector)? {
    Step::Pick(pick) => pick.id,
    Step::Reference { .. } => bail!("expected a commit selector"),
    _ => bail!("unsupported step"),
};
Defensive patterns

Strategy: type-guard

Validate before calling

match editor.lookup_step(selector)? { Step::Pick(_) => {}, _ => bail!("not a pick") }

Type guard

fn is_pick_step(editor: &Editor<impl RefMetadata>, s: Selector) -> bool {
    matches!(editor.lookup_step(s), Ok(Step::Pick(_)))
}

Try / catch

match editor.lookup_pick(selector) {
    Ok(id) => id,
    Err(_) => bail!("selector does not point at a commit pick"),
}

Prevention

When it happens

Trigger: Calling lookup_pick with a selector that normalizes to a non-Pick step — a reference/branch selector, or a stale selector whose id now points elsewhere in the editor graph.

Common situations: Scripting squash/reword operations with a selector captured for a branch; selector indices shifted after graph mutations (moves, drops) so lookups resolve to different nodes.

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/32ec16077a2b6f8d. Report an issue: GitHub.

Appendix: source

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

    pub meta: &'meta mut M,
    /// The database handle the editor was created with.
    pub db: &'meta mut but_db::DbHandle,
    /// True if a conflict occurred during checkout. This is always false if
    /// `allow_uncommitted_changes_to_conflict_with_new_head` in the options
    /// struct passed to the materialize call is false.
    pub checkout_conflict_occurred: bool,
}

/// Provides lookup for different steps that a selector might point to.
pub trait LookupStep {
    /// Look up the step that a given selector corresponds to.
    fn lookup_step(&self, selector: Selector) -> Result<Step>;

    /// Look up the step a given selector and assert it's a pick.
    fn lookup_pick(&self, selector: Selector) -> Result<gix::ObjectId> {
        match self.lookup_step(selector)? {
            Step::Pick(Pick { id, .. }) => Ok(id),
            _ => bail!("Expected selector to point to a pick"),
        }
    }

    /// Look up the step a given selector and assert it's a pick.
    fn lookup_reference(&self, selector: Selector) -> Result<gix::refs::FullName> {
        match self.lookup_step(selector)? {
            Step::Reference { refname, .. } => Ok(refname),
            _ => bail!("Expected selector to point to a reference"),
        }
    }
}

impl<M: RefMetadata> LookupStep for Editor<'_, '_, M> {
    fn lookup_step(&self, selector: Selector) -> Result<Step> {
        lookup_step(&self.graph, &self.history, selector)
    }
}

View on GitHub (pinned to 58e5313667)