gitbutlerapp/gitbutler · error
You are in conflict resolution mode. Finish with `but…
Error message
You are in conflict resolution mode. Finish with `but resolve finish` or cancel with `but resolve cancel` before using --ai.
What it means
`but resolve --ai` refuses to run while the workspace is in Edit (conflict resolution) mode. AI-assisted resolution operates on commits independently, and being mid-resolution would conflict with the in-progress resolution state, so the user must first finish or cancel it.
Solutions
- Complete the pending session: `but resolve finish`
- Or abort it: `but resolve cancel`
- Then re-run `but resolve --ai`
Example fix
// before but resolve --ai // error: You are in conflict resolution mode... // after but resolve cancel but resolve --ai
Defensive patterns
Strategy: validation
Validate before calling
// check operating mode before invoking resolve --ai
const mode = await getOperatingMode();
if (mode === 'edit') console.error('Finish with `but resolve finish` or `but resolve cancel` first'); Type guard
const canRunAiResolve = (mode) => mode !== 'edit';
Try / catch
try {
await but(['resolve', '--ai']);
} catch (e) {
if (e.message.includes('conflict resolution mode')) {
await but(['resolve', 'cancel']);
await but(['resolve', '--ai']);
} else throw e;
} Prevention
- Always close resolution sessions with `but resolve finish`/`cancel` in scripts
- Check operating mode before AI-assisted commands
- Wrap interactive sessions in try/finally to guarantee cancellation
When it happens
Trigger: Running `but resolve --ai [commit]` (resolve_with_ai via handle) when operating_mode(ctx) reports OperatingMode::Edit(_), i.e. a prior `but resolve`/edit session is still open.
Common situations: Starting an interactive resolve, abandoning it, then trying `--ai`; automation scripts that left a resolution session open.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Branch " " has no conflicted commits.
- Cannot push branch ' ': the push would include conflicted…
- Commit is not conflicted.
- Could not find stack containing commit
- In resolution mode, edit the files and run `but resolve…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/f1681c7a10cc0133.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/legacy/resolve.rs:1081
"manual": result.manual,
}))?;
}
Ok(())
}
/// Resolve conflicts with the configured AI model: one commit when
/// `commit_id_str` is given, otherwise every conflicted commit in the
/// workspace, oldest first.
fn resolve_with_ai(
ctx: &mut Context,
out: &mut OutputChannel,
commit_id_str: Option<&str>,
) -> Result<()> {
let t = theme::get();
let mode = operating_mode(ctx)?.operating_mode;
if matches!(mode, OperatingMode::Edit(_)) {
bail!(
"You are in conflict resolution mode. Finish with `but resolve finish` or cancel with `but resolve cancel` before using --ai."
);
}
let mut results = Vec::new();
if let Some(commit_id_str) = commit_id_str {
let (commit_oid, _commit_ref) = parse_commit_id(ctx, commit_id_str)?;
results.push(resolve_one_with_ai(ctx, out, commit_oid)?);
} else {
// Resolving a commit rebases its descendants, which changes their ids
// and can change (or clear) their conflicts — so re-discover the
// oldest conflicted commit after every resolution.
loop {
let Some(commit_oid) = oldest_conflicted_commit(ctx)? else {
break;
};
results.push(resolve_one_with_ai(ctx, out, commit_oid)?);
}View on GitHub (pinned to 58e5313667)