affaan-m/ECC · error
git status failed
Error message
git status failed: {stderr} What it means
git_status_entries runs `git status --porcelain=v1 --untracked-files=all` in the worktree. A non-zero exit status triggers this error carrying git's stderr. It is a thin wrapper around git, so any reason git status fails is surfaced verbatim.
Solutions
- Verify the worktree path exists and is a valid git worktree (`git -C <path> rev-parse --is-inside-work-tree`) before calling
- Recreate the worktree via create_for_session if it was pruned
- Delete a stale `<worktree>/.git/index.lock` if git reports index lock errors
- Check the stderr text in the error — 'not a git repository' vs 'index.lock' vs 'bad object' indicate different fixes
Example fix
// before
if has_staged_changes(&worktree)? { ... }
// after
if Path::new(&worktree.path).exists() && git_worktree_valid(&worktree.path)? {
if has_staged_changes(&worktree)? { ... }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the worktree is usable before git operations
fn worktree_usable(path: &Path) -> bool {
path.exists()
&& Command::new("git").arg("-C").arg(path)
.args(["rev-parse", "--is-inside-work-tree"])
.output().map(|o| o.status.success()).unwrap_or(false)
} Try / catch
match git_status_entries(&worktree) {
Ok(entries) => entries,
Err(e) if e.to_string().contains("index.lock") => {
std::fs::remove_file(worktree.path.join(".git/index.lock")).ok();
git_status_entries(&worktree)?
}
Err(e) => return Err(e),
} Prevention
- Verify the worktree path still exists before each git operation (it may have been pruned externally)
- Remove stale .git/index.lock files left by crashed git processes
- Run git operations in the worktree serially or with a per-worktree lock to avoid races
When it happens
Trigger: Calling has_staged_changes / git_status_entries on a WorktreeInfo whose path no longer exists (worktree pruned), points outside a git repository, or where the underlying git index is corrupt/locked.
Common situations: Worktree removed externally with `git worktree prune` while the session still holds its path; running in a bare repo without a worktree; a stale `.git/index.lock` left by a crashed git process; symlinked worktree path broken after a move.
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 worktree add failed
- git add failed for
- git log failed
- merge-worktree does not accept a session ID when --all is…
- Base branch is not checked out in repo root (currently )
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/4110b9aba1dee815.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/worktree/mod.rs:283
if parts.is_empty() {
Ok(Some(format!("Clean relative to {}", worktree.base_branch)))
} else {
Ok(Some(parts.join(" | ")))
}
}
pub fn git_status_entries(worktree: &WorktreeInfo) -> Result<Vec<GitStatusEntry>> {
let output = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["status", "--porcelain=v1", "--untracked-files=all"])
.output()
.context("Failed to load git status entries")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git status failed: {stderr}");
}
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(())View on GitHub (pinned to 8321021c54)