{"record":{"id":"482b5af3f0e85f27","repo":"vercel/turborepo","slug":"failed-to-run-git-diff-for-dirty-hash","errorCode":null,"errorMessage":"failed to run git diff for dirty hash","messagePattern":"failed to run git diff for dirty hash","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/turborepo-scm/src/git.rs","lineNumber":374,"sourceCode":"    fn finish_dirty_hash(&self, mut hasher: sha2::Sha256, has_status: bool) -> Option<String> {\n        use sha2::Digest;\n\n        // Try `git diff HEAD` first. In a freshly initialized repo with no\n        // commits, HEAD doesn't exist and git exits with code 128. Fall back\n        // to `git diff --cached` which diffs the index against an empty tree,\n        // correctly capturing staged file content without needing HEAD.\n        let diff_has_content = match self.stream_diff_into_hasher(\n            &[\"diff\", \"HEAD\", \"--no-ext-diff\", \"--no-color\"],\n            &mut hasher,\n        ) {\n            Some(has_content) => has_content,\n            None => match self.stream_diff_into_hasher(\n                &[\"diff\", \"--cached\", \"--no-ext-diff\", \"--no-color\"],\n                &mut hasher,\n            ) {\n                Some(has_content) => has_content,\n                None => {\n                    turborepo_log::warn(\n                        turborepo_log::Source::turbo(turborepo_log::Subsystem::Scm),\n                        \"failed to run git diff for dirty hash\",\n                    )\n                    .emit();\n                    false\n                }\n            },\n        };\n\n        if !has_status && !diff_has_content {\n            return None;\n        }\n\n        Some(hex::encode(hasher.finalize()))\n    }\n\n    /// Spawn a git diff subprocess, streaming its stdout into `hasher`.\n    /// Returns whether the diff had content, or `None` if the command failed.","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-scm/src/git.rs#L356-L392","documentation":"Continuation of the dirty-hash computation: turbo streams `git diff HEAD --no-ext-diff --no-color` into the hasher and falls back to `git diff --cached` when that is unavailable (the fallback exists to capture staged content without needing HEAD). If both attempts return None, this warning is emitted and diff_has_content becomes false, so only `git status` filenames feed the dirty hash — or the whole dirty hash is skipped when status was empty too.","triggerScenarios":"Both `git diff HEAD` and `git diff --cached` fail in the repo: broken git installation or corrupted object database, an environment where git child processes cannot run (PATH/sandbox restrictions), or a repository state in which both diff invocations error.","commonSituations":"Environments that block git subprocess spawning; corrupted .git after disk issues; exotic git versions or configs breaking diff execution; combined with error 104, a totally non-functional git setup.","solutions":["Verify both `git diff HEAD` and `git diff --cached` run cleanly in the repo","Fix git environment issues (PATH, safe.directory, reinstall git)","If .git is corrupted, re-clone the repository","Note the consequence: without diff content, cache keys rely only on git status filenames"],"exampleFix":"# before: fresh repo, no commits, both diffs fail\ngit init && turbo run build\n\n# after\ngit add -A && git commit -m 'initial commit'\nturbo run build","handlingStrategy":"validation","validationCode":"# Both diff forms must be runnable for a complete dirty hash\ngit -C \"$REPO_ROOT\" diff HEAD >/dev/null 2>&1 || echo 'git diff HEAD failed'\ngit -C \"$REPO_ROOT\" diff --cached >/dev/null 2>&1 || echo 'git diff --cached failed'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Commit at least once (`git commit --allow-empty -m init`) before running turbo in fresh repos","Verify git subprocess execution works inside sandboxes that restrict spawning","Keep .git healthy — avoid interrupting git mid-operation","If both diffs fail, expect coarser cache keys: only git status filenames feed the dirty hash"],"tags":["git","scm","cache-key","turborepo"],"backgroundTag":"git-command-failed","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}