jdx/mise · error
git diff failed: {}
Error message
git diff failed: {} What it means
In `decrypted_diff`, mise shells out to `git diff --no-index --color=never` to compare two decrypted dotfile snapshots. Git's exit codes 0 (no differences) and 1 (differences found) are both accepted; any other exit code means git itself failed (bad arguments, git not functioning, unreadable temp files). The error wraps git's stderr so the developer can see why the diff invocation broke.
Source
Thrown at src/system/history/shadow.rs:1001
&& mode != "160000"
{
right_file.write_all(&self.cat_object(oid)?)?;
}
let left_name = left_file.path().to_string_lossy().to_string();
let right_name = right_file.path().to_string_lossy().to_string();
let diff = self.git.output_unchecked(PlumbingCall::new([
"diff",
"--no-index",
"--no-ext-diff",
"--no-textconv",
"--patch",
"--color=never",
"--",
&left_name,
&right_name,
]))?;
if !matches!(diff.status.code(), Some(0 | 1)) {
bail!("git diff failed: {}", String::from_utf8_lossy(&diff.stderr));
}
let text = String::from_utf8_lossy(&diff.stdout)
.replace(left_name.trim_start_matches('/'), &left_path)
.replace(right_name.trim_start_matches('/'), &right_path);
output.extend_from_slice(text.as_bytes());
if left.as_ref().map(|v| &v.0) != right.as_ref().map(|v| &v.0) {
output.extend_from_slice(
format!(
"{right_path}: mode {} -> {}\n",
left.as_ref().map_or("absent", |v| v.0.as_str()),
right.as_ref().map_or("absent", |v| v.0.as_str())
)
.as_bytes(),
);
}
}
Ok(DiffResult { output, changed })
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Run `git diff --no-index --color=never <left> <right>` manually on the two paths from the error context and read the stderr shown in the message.
- Verify `git --version` works and no global git config (e.g. a broken external diff driver) interferes.
- Check that the temporary directory holding the decrypted snapshots exists and is readable/writable by the current user.
- Retry the dotfile diff command; if it persists, report with the captured stderr.
Example fix
// before: opaque failure
let diff = cmd_output(...)?;
if !matches!(diff.status.code(), Some(0 | 1)) {
bail!("git diff failed: {}", String::from_utf8_lossy(&diff.stderr));
}
// after (caller-side): pre-check inputs and git availability
if !left_path.exists() || !right_path.exists() {
eprintln!("snapshot missing; re-running sync");
}
assert!(Command::new("git").arg("--version").output().is_ok()); Defensive patterns
Strategy: try-catch
Validate before calling
if !Command::new("git").arg("--version").output().map(|o| o.status.success()).unwrap_or(false) {
eprintln!("git unavailable; diff will fail");
}
assert!(left_path.exists() && right_path.exists()); Type guard
fn diffable(left: &Path, right: &Path) -> bool { left.exists() && right.exists() } Try / catch
match store.diff(&left, &right) {
Ok(text) => display(text),
Err(e) if e.to_string().contains("git diff failed") => eprintln!("git diff broke: check git install/temp dir: {e}"),
Err(e) => return Err(e),
} Prevention
- Keep a working `git` on PATH and avoid broken global diff-driver config
- Ensure the temp directory used for decrypted snapshots is writable
- Don't delete temp snapshot files while a diff is in flight
When it happens
Trigger: Calling `diff` on two shadow-history snapshots when the spawned `git diff` process exits with a code other than 0 or 1 — e.g. git is missing/broken, the temp file paths are invalid or deleted mid-diff, or an invalid diff option is in effect.
Common situations: A corrupt or pruned temp directory removes one of the compared files before git reads it; a system git is too old or misconfigured (broken global diff driver); a sandboxed environment blocks process spawning or /tmp access.
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
- git merge-file failed: {}
- git command failed with {status}
- git clone failed with {status}
- comparing checkpoints requires git
- listing snapshot files requires git
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/da136197bd615ad4.
Report an issue: GitHub.