jdx/mise · error

Git difftool failed ( )

Error message

Git difftool failed ({status})

What it means

The conflicts command shells out to `git difftool` to show local-vs-remote sides of a conflict. Git difftool may exit 1 when the sides differ (treated as success), but any other exit code or signal causes a bail with the exit status.

Solutions

  1. Check the configured difftool (`git config diff.tool`, `difftool.<tool>.cmd`) and fix or switch to a working tool (e.g. `git config diff.tool vimdiff`)
  2. Run the difftool manually on the two file paths from the error context to see its real error
  3. Ensure the difftool exists on PATH and works headless (set a CLI-based tool in SSH/CI environments)
  4. Re-run `mise dot conflicts` after fixing the difftool config

Example fix

// before
$ git config diff.tool kaleidoscope   # GUI tool, not installed
$ mise dot conflicts
error: Git difftool failed (exit status: 127)
// after
$ git config --global diff.tool vimdiff
$ mise dot conflicts
Defensive patterns

Strategy: try-catch

Validate before calling

git difftool --tool-help >/dev/null 2>&1 && echo "difftool configured" || echo "configure diff.tool"

Try / catch

match result {
    Err(e) if e.to_string().contains("Git difftool failed") => {
        // fix git diff.tool config or PATH, then retry
    }
    ...
}

Prevention

When it happens

Trigger: `git difftool` exits with a code other than 0 or 1 while `mise dot conflicts` renders a conflict diff — usually a misconfigured diff tool or difftool erroring on the given files.

Common situations: `diff.tool` configured to a GUI tool unavailable headless; difftool command not found; difftool crashed on binary/huge files; custom difftool exits with a nonstandard code.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/a0bafaedbc08d579. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/dotfiles/conflicts.rs:144

    let local = side_file(repo, conflict.local.as_ref(), path, "local")?;
    let remote = side_file(repo, conflict.remote.as_ref(), path, "remote")?;
    let git = crate::git::plumbing_binary().ok_or_else(|| eyre::eyre!("git is unavailable"))?;
    let mut command = Command::new(git);
    crate::git::sanitize_git_command(&mut command);
    command
        .current_dir(repo.dir().parent().unwrap_or(repo.dir()))
        .args(["difftool", "--no-prompt"]);
    if let Some(tool) = tool {
        command.arg("--tool").arg(tool);
    }
    command.arg("--no-index").arg("--");
    command.arg(local.file.path()).arg(remote.file.path());
    let status = command
        .status()
        .wrap_err_with(|| format!("running Git conflict difftool for {}", display_path(path)))?;
    // Like `git diff --no-index`, difftool exits 1 when the sides differ.
    if !matches!(status.code(), Some(0 | 1)) {
        bail!("Git difftool failed ({status})");
    }
    if local.mode != remote.mode {
        miseprintln!("mode: {} -> {}", local.mode, remote.mode);
    }
    Ok(())
}

struct SideFile {
    file: tempfile::NamedTempFile,
    mode: String,
    label: String,
}

fn side_file(
    repo: &HistoryRepo,
    object: Option<&Object>,
    path: &Path,
    side: &str,

View on GitHub (pinned to 533346cc37)