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

  1. Verify the worktree path exists and is a valid git worktree (`git -C <path> rev-parse --is-inside-work-tree`) before calling
  2. Recreate the worktree via create_for_session if it was pruned
  3. Delete a stale `<worktree>/.git/index.lock` if git reports index lock errors
  4. 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

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


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)