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

  1. Complete the pending session: `but resolve finish`
  2. Or abort it: `but resolve cancel`
  3. 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

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


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)