{"record":{"id":"da136197bd615ad4","repo":"jdx/mise","slug":"git-diff-failed-da1361","errorCode":null,"errorMessage":"git diff failed: {}","messagePattern":"git diff failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":1001,"sourceCode":"                && mode != \"160000\"\n            {\n                right_file.write_all(&self.cat_object(oid)?)?;\n            }\n            let left_name = left_file.path().to_string_lossy().to_string();\n            let right_name = right_file.path().to_string_lossy().to_string();\n            let diff = self.git.output_unchecked(PlumbingCall::new([\n                \"diff\",\n                \"--no-index\",\n                \"--no-ext-diff\",\n                \"--no-textconv\",\n                \"--patch\",\n                \"--color=never\",\n                \"--\",\n                &left_name,\n                &right_name,\n            ]))?;\n            if !matches!(diff.status.code(), Some(0 | 1)) {\n                bail!(\"git diff failed: {}\", String::from_utf8_lossy(&diff.stderr));\n            }\n            let text = String::from_utf8_lossy(&diff.stdout)\n                .replace(left_name.trim_start_matches('/'), &left_path)\n                .replace(right_name.trim_start_matches('/'), &right_path);\n            output.extend_from_slice(text.as_bytes());\n            if left.as_ref().map(|v| &v.0) != right.as_ref().map(|v| &v.0) {\n                output.extend_from_slice(\n                    format!(\n                        \"{right_path}: mode {} -> {}\\n\",\n                        left.as_ref().map_or(\"absent\", |v| v.0.as_str()),\n                        right.as_ref().map_or(\"absent\", |v| v.0.as_str())\n                    )\n                    .as_bytes(),\n                );\n            }\n        }\n        Ok(DiffResult { output, changed })\n    }","sourceCodeStart":983,"sourceCodeEnd":1019,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/shadow.rs#L983-L1019","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: opaque failure\nlet diff = cmd_output(...)?;\nif !matches!(diff.status.code(), Some(0 | 1)) {\n    bail!(\"git diff failed: {}\", String::from_utf8_lossy(&diff.stderr));\n}\n// after (caller-side): pre-check inputs and git availability\nif !left_path.exists() || !right_path.exists() {\n    eprintln!(\"snapshot missing; re-running sync\");\n}\nassert!(Command::new(\"git\").arg(\"--version\").output().is_ok());","handlingStrategy":"try-catch","validationCode":"if !Command::new(\"git\").arg(\"--version\").output().map(|o| o.status.success()).unwrap_or(false) {\n    eprintln!(\"git unavailable; diff will fail\");\n}\nassert!(left_path.exists() && right_path.exists());","typeGuard":"fn diffable(left: &Path, right: &Path) -> bool { left.exists() && right.exists() }","tryCatchPattern":"match store.diff(&left, &right) {\n    Ok(text) => display(text),\n    Err(e) if e.to_string().contains(\"git diff failed\") => eprintln!(\"git diff broke: check git install/temp dir: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["git","subprocess","dotfiles","diff"],"backgroundTag":"git-command-failed","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}