{"record":{"id":"e3fbd8372b563a26","repo":"nikivdev/code","slug":"git-diff-cached-name-only-failed","errorCode":null,"errorMessage":"git diff --cached --name-only failed","messagePattern":"git diff --cached --name-only failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/gitignore_policy.rs","lineNumber":459,"sourceCode":"\n            if line.starts_with(' ') {\n                line_no = line_no.saturating_add(1);\n            }\n        }\n    }\n\n    Ok(violations)\n}\n\nfn staged_gitignore_files(repo_root: &Path) -> Result<Vec<String>> {\n    let output = Command::new(\"git\")\n        .current_dir(repo_root)\n        .args([\"diff\", \"--cached\", \"--name-only\", \"--diff-filter=ACMR\"])\n        .output()\n        .context(\"failed to list staged files\")?;\n\n    if !output.status.success() {\n        bail!(\"git diff --cached --name-only failed\")\n    }\n\n    Ok(String::from_utf8_lossy(&output.stdout)\n        .lines()\n        .map(str::trim)\n        .filter(|s| s.ends_with(\".gitignore\"))\n        .map(|s| s.to_string())\n        .collect())\n}\n\nfn inspect_repo_gitignores(repo_root: &Path, policy: &GitignorePolicy) -> Result<Vec<Violation>> {\n    let blocked = blocked_lookup(policy);\n    let files = list_gitignore_files(repo_root);\n    let mut out = Vec::new();\n\n    for file in files {\n        let content = fs::read_to_string(&file)\n            .with_context(|| format!(\"failed to read {}\", file.display()))?;","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/gitignore_policy.rs#L441-L477","documentation":"`staged_gitignore_files` shells out to `git diff --cached --name-only --diff-filter=ACMR` inside the repository root to list staged .gitignore files. When the subprocess exits with a non-zero status, the function bails with this message. This is not a parse error of the diff output itself — it means git itself rejected the invocation.","triggerScenarios":"Running `git diff --cached` while not inside a git repository or in a repo whose .git dir is unreadable; a corrupt or locked git index (e.g. stale index.lock); a git version that does not support the flags; git exiting due to safe.directory ownership restrictions.","commonSituations":"Calling this helper from outside a git repo (repo_root mis-detected or a parent path passed in); running during a git operation that holds an index lock (rebase/merge in progress); CI containers where the checkout is owned by a different user than the process.","solutions":["Verify the process runs inside a valid git repository: `git -C <repo_root> rev-parse --is-inside-work-tree`","Check for a stale lock file and remove it: `rm <repo_root>/.git/index.lock` (only when no git process is running)","If on a CI container, add the checkout dir to safe.directory: `git config --global --add safe.directory <repo_root>`","Run the exact command manually to see git's real error: `git -C <repo_root> diff --cached --name-only --diff-filter=ACMR`"],"exampleFix":"// before\nlet output = Command::new(\"git\")\n    .args([\"diff\", \"--cached\", \"--name-only\", \"--diff-filter=ACMR\"])\n    .current_dir(repo_root)\n    .output()\n    .context(\"failed to list staged files\")?;\n// after\nlet output = Command::new(\"git\")\n    .args([\"-C\", repo_root.to_str().unwrap(), \"rev-parse\", \"--is-inside-work-tree\"])\n    .output()?;\nanyhow::ensure!(output.status.success(), \"not a git repo: {}\", repo_root.display());\nlet output = Command::new(\"git\")\n    .args([\"diff\", \"--cached\", \"--name-only\", \"--diff-filter=ACMR\"])\n    .current_dir(repo_root)\n    .output()\n    .context(\"failed to list staged files\")?;","handlingStrategy":"try-catch","validationCode":"let ok = Command::new(\"git\")\n    .args([\"-C\", repo_root.to_str().unwrap(), \"rev-parse\", \"--is-inside-work-tree\"])\n    .output()\n    .map(|o| o.status.success())\n    .unwrap_or(false);\nif !ok { anyhow::bail!(\"{} is not a usable git repository\", repo_root.display()); }","typeGuard":"fn is_git_repo(repo_root: &Path) -> bool {\n    repo_root.join(\".git\").exists()\n        && Command::new(\"git\")\n            .args([\"-C\", repo_root.to_str().unwrap(), \"rev-parse\", \"--git-dir\"])\n            .output()\n            .map(|o| o.status.success())\n            .unwrap_or(false)\n}","tryCatchPattern":"match staged_gitignore_files(repo_root) {\n    Ok(files) => process(files),\n    Err(e) if e.to_string().contains(\"git diff --cached\") => {\n        eprintln!(\"git unavailable/index locked: {e:#}\");\n        eprintln!(\"hint: check for .git/index.lock or run outside a repo\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always verify the working directory is a git repo before running staged-file helpers","Check for `.git/index.lock` before invoking git index operations","Add `safe.directory` config in CI containers running as a different user","Surface the child process's stderr in the error, not just a static message"],"tags":["git","subprocess","rust","anyhow"],"backgroundTag":"git-command-failed","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}