gitbutlerapp/gitbutler · error

Reference target in rebase result is not a commit

Error message

Reference target in rebase result is not a commit

What it means

reference_target finds the first ordered parent of a reference step in the materialized result graph and expects that parent node to be a Step::Pick whose commit is the ref's target. If the parent exists but is not a Pick, the ref target cannot be expressed as a commit id and the library bails.

Solutions

  1. Ensure the reference is a child of a Pick (commit) step before querying its target
  2. Attach or move the reference so its parent is a commit pick in the graph
  3. Use lookup_reference if you only need the ref name, not its target commit

Example fix

// before
let target = editor.reference_target(branch_selector)?; // parent isn't a Pick
// after
let parents = collect_ordered_parents(&editor.graph, branch_selector);
if parents.iter().any(|p| !matches!(editor.graph[*p], Step::Pick(_))) {
    // first move the branch under a commit pick
}
let target = editor.reference_target(branch_selector)?;
Defensive patterns

Strategy: validation

Validate before calling

let parent = collect_ordered_parents(&editor.graph, reference).into_iter().next()
    .ok_or_else(|| anyhow!("reference has no parent"))?;
if !matches!(editor.graph[parent], Step::Pick(_)) { return Err(anyhow!("parent is not a pick")); }

Type guard

fn parent_is_pick(graph: &Graph, reference: Selector) -> bool {
    collect_ordered_parents(graph, reference).first()
        .map(|p| matches!(graph[*p], Step::Pick(_)))
        .unwrap_or(false)
}

Try / catch

match editor.reference_target(sel) {
    Ok(id) => id,
    Err(_) => { /* move the reference under a commit pick, then retry */ }
}

Prevention

When it happens

Trigger: Calling reference_target (e.g. via move_branch_in_single_branch_mode) on a reference whose first parent in the result graph is not a Pick step — for instance the ref hangs off a special/root step or another Reference node instead of a commit.

Common situations: Moving a branch onto a position in the graph where the nearest parent is another reference or a non-commit step; querying the target of a freshly added reference that has not been attached to a commit yet.

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

Appendix: source

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

    /// Return the commit targeted by `ref_name` in the post-rebase step graph.
    pub fn reference_target(&self, ref_name: &gix::refs::FullNameRef) -> Result<gix::ObjectId> {
        let reference = self
            .graph
            .node_indices()
            .find(|node| {
                matches!(
                    &self.graph[*node],
                    Step::Reference { refname, .. } if refname == ref_name
                )
            })
            .with_context(|| format!("Could not find reference '{ref_name}' in rebase result"))?;
        let parent = collect_ordered_parents(&self.graph, reference)
            .into_iter()
            .next()
            .context("Reference has no target commit in rebase result")?;
        match self.graph[parent] {
            Step::Pick(Pick { id, .. }) => Ok(id),
            _ => bail!("Reference target in rebase result is not a commit"),
        }
    }

    /// Returns a preview of what the but-graph will look like after
    /// materialization.
    ///
    /// Any objects referenced in the resulting graph must be accessed via the
    /// in-memory repository owned by this [`SuccessfulRebase`] (`self.repo`),
    /// since they might exist only in memory.
    pub fn overlayed_graph(&self) -> Result<but_graph::Graph> {
        self.overlayed_graph_with_workspace_overrides(None, None)
    }

    /// Return the post-rebase graph with optional ad-hoc workspace projection overrides.
    ///
    /// This is useful for dry-run operations whose graph rewrite is accompanied by metadata or
    /// checkout changes that are deliberately not persisted. The override entrypoint must name the
    /// commit and local reference that would be checked out, while `branch_stack_order` supplies the

View on GitHub (pinned to 58e5313667)