gitbutlerapp/gitbutler · error
A matching parent can't be found in the output graph
Error message
A matching parent can't be found in the output graph
What it means
During rebase, a pick's parents are mapped from the input graph to the output graph via graph_mapping. When a pick has no preserved_parents, each graph parent must map to a node in the output graph; an unmapped index means the new parentage cannot be computed, so the rebase bails rather than guessing parents.
Solutions
- Ensure all parents of kept picks are also present in the output graph (don't drop ancestors of kept commits)
- Provide preserved_parents explicitly for picks whose parent mapping you control
- Recompute graph_mapping after any node removals before running rebase
Example fix
// before: parent dropped from output graph
output_graph.drop(parent_selector)?;
rebase(&graph, &output_graph)?;
// after: keep ancestors or remap children first
let mapped = graph_mapping.get(&parent_idx)
.context("parent missing; re-add or remap before rebase")?;
rebase(&graph, &output_graph)?; Defensive patterns
Strategy: validation
Validate before calling
for idx in graph_parents {
if !graph_mapping.contains_key(&idx) {
return Err(anyhow!("parent {} missing from output graph", idx));
}
} Type guard
fn parents_mapped(graph_parents: &[usize], mapping: &HashMap<usize, usize>) -> bool {
graph_parents.iter().all(|p| mapping.contains_key(p))
} Try / catch
let new_idx = graph_mapping.get(&idx)
.ok_or_else(|| anyhow!("parent dropped from output graph; re-add or set preserved_parents"))?; Prevention
- Never drop ancestor picks while keeping their descendants
- Set preserved_parents explicitly for picks with custom parentage
- Recompute the graph mapping after any output-graph node removal
When it happens
Trigger: Calling rebase (public) when an input-graph parent index of a pick is absent from graph_mapping — typically because that parent node was dropped/filtered from the output graph (e.g. an ancestor pick removed) while descendants still reference it.
Common situations: Dropping or filtering out parent commits from the rebase plan while children still depend on them; custom step transformations that remove nodes without remapping descendant parentage; bugs in callers building the output graph.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- A parent in the output graph is not a pick
- An edge with desired order
- Cannot order selected commits by parentage: selected commit
- Failed to find corresponding parent
- Invalid parent delimitation: requested child is not a…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/3350537f6efe15c1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-rebase/src/graph_rebase/rebase.rs:48
for step_idx in steps_to_pick {
// Do the frikkin rebase man!
let step = self.graph[step_idx].clone();
let new_idx = match step {
Step::Pick(pick) if !pick.mutable => {
// Immutable picks are copied verbatim: the commit keeps its
// id, so there's no cherry-pick to run and nothing to record
// in the history mapping.
output_graph.add_node(Step::Pick(pick))
}
Step::Pick(pick) => {
let graph_parents = collect_ordered_parents(&self.graph, step_idx);
let ontos = match pick.preserved_parents.clone() {
Some(ontos) => ontos,
None => graph_parents
.iter()
.map(|idx| {
let Some(new_idx) = graph_mapping.get(idx) else {
bail!("A matching parent can't be found in the output graph");
};
match output_graph[*new_idx] {
Step::Pick(Pick { id, .. }) => Ok(id),
_ => bail!("A parent in the output graph is not a pick"),
}
})
.collect::<Result<Vec<_>>>()?,
};
let outcome = cherry_pick(
&self.repo,
pick.id,
&ontos,
pick.pick_mode,
pick.tree_merge_mode,
pick.sign_commit,
)?;View on GitHub (pinned to 58e5313667)