{"record":{"id":"64baa36efbf5a814","repo":"vercel/turborepo","slug":"failed-to-get-git-status-for-dirty-hash-e","errorCode":null,"errorMessage":"failed to get git status for dirty hash: {e}","messagePattern":"failed to get git status for dirty hash: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/turborepo-scm/src/git.rs","lineNumber":238,"sourceCode":"    /// Compute a hash summarizing all uncommitted state in the working tree.\n    /// Uses `git status --porcelain -z` (which files are dirty/untracked) and\n    /// `git diff HEAD` (the actual content changes for tracked files) as inputs\n    /// to a SHA-256 hash. Returns `None` if the working tree is clean or if\n    /// git commands fail (with a warning logged).\n    ///\n    /// The diff output is streamed through the hasher to avoid buffering\n    /// arbitrarily large diffs into memory. `--no-ext-diff` and `--no-binary`\n    /// ensure deterministic, bounded output regardless of user git config.\n    ///\n    /// Note: content of untracked files (not yet `git add`ed) is not included\n    /// in the diff — only their filenames from `git status` contribute.\n    fn get_dirty_hash(&self) -> Option<String> {\n        use sha2::{Digest, Sha256};\n\n        let status_output = match self.execute_git_command(&[\"status\", \"--porcelain\", \"-z\"], \"\") {\n            Ok(output) => output,\n            Err(e) => {\n                turborepo_log::warn(\n                    turborepo_log::Source::turbo(turborepo_log::Subsystem::Scm),\n                    format!(\"failed to get git status for dirty hash: {e}\"),\n                )\n                .emit();\n                return None;\n            }\n        };\n\n        if status_output.is_empty() {\n            return None;\n        }\n\n        let mut hasher = Sha256::new();\n        hasher.update(&status_output);\n        self.finish_dirty_hash(hasher, true)\n    }\n\n    fn get_dirty_hash_from_repo_index(&self, repo_index: &RepoGitIndex) -> Option<String> {","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-scm/src/git.rs#L220-L256","documentation":"Part of the SCM dirty-hash computation that makes cache keys more conservative for modified workspaces: turbo runs `git status --porcelain -z` and mixes the result into a hash of the working-tree state. If that git command errors, turbo emits this warning and returns None, so the dirty state contributes nothing to the cache key. Caching still works, but it is less precise about local modifications.","triggerScenarios":"`execute_git_command([\"status\", \"--porcelain\", \"-z\"])` fails in the repo root: git not installed or not on PATH, the directory not actually a git repository (or .git corrupted), or git refusing to run due to 'dubious ownership' (safe.directory).","commonSituations":"Slim CI images without git; a checkout created outside the container while turbo runs inside; files owned by root vs the container user triggering safe.directory; a broken .git after interrupted operations.","solutions":["Verify git works in the same environment: run `git status --porcelain` in the repo root","For ownership errors run `git config --global --add safe.directory /path/to/repo`","Install git in the CI image or add it to PATH","If .git is corrupted, re-clone the repository"],"exampleFix":"# before: dubious ownership error\nfatal: detected dubious ownership in repository at '/repo'\n\n# after\ngit config --global --add safe.directory /repo\nturbo run build","handlingStrategy":"validation","validationCode":"# Confirm git works where turbo will run\ngit -C \"$REPO_ROOT\" status --porcelain >/dev/null \\\n  || { echo 'git status failed — fix before turbo'; exit 1; }\nturbo run build","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Include git in CI images that run turbo","For containers sharing a host checkout, set `git config --global --add safe.directory <repo>`","Avoid running turbo against a .git owned by a different user","Know the consequence: a failed status read removes the dirty-state contribution from cache keys"],"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"}