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
- Ensure the reference is a child of a Pick (commit) step before querying its target
- Attach or move the reference so its parent is a commit pick in the graph
- 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
- Only query targets of references attached to commit picks
- Move references before mutating their parents
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
- A matching parent can't be found in the output graph
- A parent in the output graph is not a pick
- An edge with desired order
- Cannot order selected commits by parentage: selected commit
- Expected selector for
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 theView on GitHub (pinned to 58e5313667)