gitbutlerapp/gitbutler · error
Commit {} was marked as not conflictable, but resulted in a
Error message
Commit {} was marked as not conflictable, but resulted in a conflicted state What it means
Each pick in a graph rebase plan carries a `conflictable` flag declaring whether a conflicted outcome is acceptable for that commit. When the cherry pick of a commit marked not-conflictable nevertheless produces a conflicted commit, the rebase bails: the plan's assumptions no longer match the history being rebased (typically a plan built over a stale graph).
Source
Thrown at crates/but-rebase/src/graph_rebase/rebase.rs:74
_ => 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,
)?;
if matches!(outcome, CherryPickOutcome::ConflictedCommit(_))
&& !pick.conflictable
{
bail!(
"Commit {} was marked as not conflictable, but resulted in a conflicted state",
pick.id
);
}
match outcome {
CherryPickOutcome::Commit(new_id)
| CherryPickOutcome::ConflictedCommit(new_id)
| CherryPickOutcome::Identity(new_id) => {
let mut new_pick = pick.clone();
new_pick.id = new_id;
let new_idx = output_graph.add_node(Step::Pick(new_pick));
graph_mapping.insert(step_idx, new_idx);
if !pick.exclude_from_tracking {
history.update_mapping(pick.id, new_id);
}
new_idxView on GitHub (pinned to caf1f223d3)
Solutions
- Rebuild the graph and plan from the current state, then execute the fresh plan
- Mark such picks conflictable if conflicts are genuinely tolerable for this flow
- Serialize planning and execution so no ref updates land in between
Example fix
// before: execute a plan captured earlier editor.rebase(&stale_plan)?; // may hit the not-conflictable invariant // after: rebuild the plan right before execution let graph = but_graph::Graph::from_repo(&repo)?; let plan = build_plan(&graph); editor.rebase(&plan)?;
Defensive patterns
Strategy: retry
Validate before calling
// Rust: build the plan immediately before executing it, from a fresh graph let graph = but_graph::Graph::from_repo(&repo)?; let plan = build_plan(&graph); // conflictable flags reflect current state editor.rebase(&plan)?;
Try / catch
On this invariant bail, discard the plan, rebuild graph + plan from current state, and retry once; if it reproduces, report a bug including the commit id from the message.
Prevention
- Never cache plans across ref updates; plan and execute in one locked window
- Hold the workspace/repository lock from planning through execution to bar concurrent ref changes
When it happens
Trigger: Executing a plan where `conflictable=false` for a commit whose pick returns `CherryPickOutcome::ConflictedCommit` — history or refs changed between plan creation and execution.
Common situations: Plans computed from cached graphs; refs updated by another window or a background fetch between planning and execution; concurrent worktrees sharing objects.
Related errors
- in commit {}, number of sides ({}) is not exactly one more t
- Cherry picks can only be done for single-parent commits. Mer
- Failed to merge bases while cherry picking commit {target}.
- commits cannot be moved to the merge base
- Encountered conflict when merging tree {tree_to_merge}{detai
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/caf363e38b6ba729.
Report an issue: GitHub.