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

git worktree add failed: {stderr}

Error message

git worktree add failed: {stderr}

What it means

The worktree creator runs `git -C <repo> worktree add -b <branch> <path> HEAD` and it exited non-zero. The full git stderr is interpolated into the message, so the precise git-level cause is in {stderr}.

Source

Thrown at ecc2/src/worktree/mod.rs:126

    // Get current branch as base
    let base = get_current_branch(repo_root)?;

    std::fs::create_dir_all(&cfg.worktree_root)
        .context("Failed to create worktree root directory")?;

    let output = Command::new("git")
        .arg("-C")
        .arg(repo_root)
        .args(["worktree", "add", "-b", &branch])
        .arg(&path)
        .arg("HEAD")
        .output()
        .context("Failed to run git worktree add")?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("git worktree add failed: {stderr}");
    }

    tracing::info!(
        "Created worktree at {} on branch {}",
        path.display(),
        branch
    );

    let info = WorktreeInfo {
        path,
        branch,
        base_branch: base,
    };

    if let Err(error) = sync_shared_dependency_dirs_in_repo(&info, repo_root) {
        tracing::warn!(
            "Shared dependency cache sync warning for {}: {error}",
            info.path.display()

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Read the embedded {stderr} first — it names the exact git-level cause.
  2. If the branch already exists, reuse it or delete it (git branch -D) before retrying.
  3. Prune stale worktrees with `git worktree prune` and remove the target path if it is a leftover directory.
  4. Validate the branch name and path with git check-ref-format / path sanity before invoking git.

Example fix

// before
let info = create_worktree(repo_root, &path, &branch, base)?;

// after
// pre-flight: ensure no stale worktree/branch blocks creation
let _ = Command::new("git").arg("-C").arg(repo_root)
    .args(["worktree", "prune"]).status();
let branch_taken = Command::new("git").arg("-C").arg(repo_root)
    .args(["rev-parse", "--verify", "--quiet", &format!("refs/heads/{branch}")])
    .status()?.success();
if branch_taken {
    anyhow::bail!("branch {branch} already exists; reuse or delete it first");
}
let info = create_worktree(repo_root, &path, &branch, base)?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight checks that mirror git's own constraints.
use std::process::Command;

fn branch_exists(repo_root: &Path, branch: &str) -> bool {
    Command::new("git").arg("-C").arg(repo_root)
        .args(["rev-parse", "--verify", "--quiet", &format!("refs/heads/{branch}")])
        .status().map(|s| s.success()).unwrap_or(false)
}

if branch_exists(repo_root, &branch) {
    return Err(anyhow::anyhow!("branch {branch} already exists; reuse or delete it first"));
}
if path.exists() {
    return Err(anyhow::anyhow!("worktree path {} already exists", path.display()));
}

Type guard

fn worktree_creation_preconditions_ok(repo_root: &Path, path: &Path, branch: &str) -> bool {
    !branch_exists(repo_root, branch) && !path.exists()
}

Try / catch

match create_worktree(repo_root, &path, &branch, base) {
    Ok(info) => { /* created */ }
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("git worktree add failed") {
            // msg already embeds git's stderr; branch on it:
            // - "already exists" -> prune / delete branch / pick a new path and retry
            // - "not a valid object name HEAD" -> ensure HEAD has a commit (non-bare repo)
            // - permission/disk -> fix environment
        }
        return Err(e);
    }
}

Prevention

When it happens

Trigger: git worktree add fails: the branch already exists; the path is inside an existing worktree or is non-empty; HEAD is unborn (no commits) or detached in a bare repo; permission/disk errors; invalid characters in branch or path.

Common situations: Reusing a session_id whose branch already exists from a prior run; a previous crash left a worktree at that path; invalid branch-name characters; running against a fresh/bare clone with no HEAD commit.

Related errors


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