affaan-m/ECC · error · anyhow::Error

git status failed: {stderr}

Error message

git status failed: {stderr}

What it means

git_status_entries shells out to `git -C <worktree.path> status --porcelain=v1 --untracked-files=all` and re-throws git's stderr when the process exits non-zero. It is the foundation for nearly every status-driven operation (staging, commit readiness, health), so a failure here cascades upstream. The error message is git's own stderr, so the underlying cause is usually visible in the message text.

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 01e15490f0)

Solutions

  1. Check that `worktree.path` is still an existing directory before calling (e.g. `if !worktree.path.is_dir() { ... }`).
  2. Remove a stale `.git/index.lock` if present: `rm -f <repo>/.git/index.lock` after confirming no git process is running.
  3. Re-resolve the WorktreeInfo via create_for_session / the session store if the worktree was recreated or its path changed.
  4. Verify filesystem permissions and that the path is inside a repo (`git -C <path> rev-parse --is-inside-work-tree`).

Example fix

// before
let entries = git_status_entries(&worktree)?;

// after
if !worktree.path.is_dir() {
    anyhow::bail!("worktree path missing: {}", worktree.path.display());
}
let entries = git_status_entries(&worktree)?;
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;

fn ensure_worktree_usable(path: &Path) -> anyhow::Result<()> {
    if !path.is_dir() {
        anyhow::bail!("worktree path is not a directory: {}", path.display());
    }
    let lock = path.join(".git").join("index.lock");
    // Also handle a gitdir file for linked worktrees
    if lock.exists() {
        anyhow::bail!("stale index.lock present: {}", lock.display());
    }
    Ok(())
}

// call before git_status_entries
ensure_worktree_usable(&worktree.path)?;
let entries = git_status_entries(&worktree)?;

Try / catch

match git_status_entries(&worktree) {
    Ok(entries) => { /* proceed */ }
    Err(e) => {
        // Distinguish spawn-failure (.context) from git-failure (bail!).
        if format!("{e:#}").contains("git status failed") {
            // surface to user as 'repo/worktree unusable'
        }
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling git_status_entries, has_staged_changes, health, or diff_file_preview on a WorktreeInfo whose path no longer exists, is not inside a git repository, has a stale `.git/index.lock`, or is unreadable by the current process. Also triggered when the worktree was pruned/deleted out of band while a session still holds a stale WorktreeInfo handle.

Common situations: Worktree removed manually (rm -rf) or via `git worktree prune` while the session keeps an old WorktreeInfo; a previous git process crashed and left `.git/index.lock`; CI/container runs as a different uid than the worktree owner; the worktree path was a symlink whose target moved.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/4110b9aba1dee815. Report an issue: GitHub.