affaan-m/ECC · error
git add failed for
Error message
git add failed for {path}: {stderr} What it means
stage_path runs `git add -- <path>` inside the worktree and, on non-zero exit, includes both the offending path and git's stderr in the error. Untracked-but-ignored paths, pathspec errors, and index lock conflicts all land here.
Solutions
- Check the file exists and is not gitignored before staging (`git -C <path> check-ignore <file>`; use force-add intentionally if needed)
- Retry after the concurrent git operation completes if stderr mentions index.lock
- Ensure the path is relative to the worktree root and points inside it
- Quote/normalize the path so it cannot be misread as a git option
Example fix
// before
stage_path(&worktree, "build/output.log")?; // ignored file
// after
if !is_ignored(&worktree, "build/output.log")? {
stage_path(&worktree, "build/output.log")?;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the path before staging
fn stageable(worktree: &WorktreeInfo, path: &str) -> bool {
worktree.path.join(path).exists()
&& !Command::new("git").arg("-C").arg(&worktree.path)
.args(["check-ignore", path]).output()
.map(|o| o.status.success()).unwrap_or(false)
} Try / catch
match stage_path(&worktree, path) {
Ok(()) => (),
Err(e) if e.to_string().contains("index.lock") => {
wait_and_retry_stage(&worktree, path)?;
}
Err(e) => return Err(e),
} Prevention
- Confirm the file exists and is not gitignored before staging; use git add -f deliberately when needed
- Ensure paths are relative to the worktree root and normalized (no leading '-')
- Serialize git index operations per worktree to avoid index.lock collisions
- Re-read status after external changes instead of staging a cached path list
When it happens
Trigger: Calling stage_path with a path that does not exist in the worktree, is excluded by .gitignore, matches no pathspec, or while a git index.lock is held by another process.
Common situations: Staging a file that was deleted before the call; staging a file listed in .gitignore (git add refuses without -f); two concurrent session operations racing on the same worktree index; a path with characters that confuse the pathspec (e.g. leading '-').
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 status failed
- git worktree add failed
- Claude Code did not expose a process id
- ECC runner did not expose a process id
- git log failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/3ccb7686a55b59ba.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/worktree/mod.rs:304
Ok(String::from_utf8_lossy(&output.stdout)
.lines()
.filter_map(parse_git_status_entry)
.collect())
}
pub fn stage_path(worktree: &WorktreeInfo, path: &str) -> Result<()> {
let output = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["add", "--"])
.arg(path)
.output()
.with_context(|| format!("Failed to stage {}", path))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git add failed for {path}: {stderr}");
}
}
pub fn unstage_path(worktree: &WorktreeInfo, path: &str) -> Result<()> {
let output = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["reset", "HEAD", "--"])
.arg(path)
.output()
.with_context(|| format!("Failed to unstage {}", path))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git reset failed for {path}: {stderr}");
}
}View on GitHub (pinned to 8321021c54)