affaan-m/ECC · error

{stderr}

Error message

{stderr}

What it means

Thrown by validate_branch_name at ecc2/src/worktree/mod.rs:1493 when `git check-ref-format --branch <branch>` fails AND git produced a non-empty stderr. Unlike the generic sibling (768), this branch trusts git's own diagnostic and re-emits it verbatim as the bail message. Common stderr texts include 'fatal: <name> is not a valid branch name' and refs/heads/ prefix collisions.

Source

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

    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}

fn validate_branch_name(repo_root: &Path, branch: &str) -> Result<()> {
    let output = Command::new("git")
        .arg("-C")
        .arg(repo_root)
        .args(["check-ref-format", "--branch", branch])
        .output()
        .context("Failed to validate worktree branch name")?;

    if output.status.success() {
        Ok(())
    } else {
        let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
        if stderr.is_empty() {
            anyhow::bail!("branch name is not a valid git ref");
        } else {
            anyhow::bail!("{stderr}");
        }
    }
}

fn parse_git_status_entry(line: &str) -> Option<GitStatusEntry> {
    if line.len() < 4 {
        return None;
    }
    let bytes = line.as_bytes();
    let index_status = bytes[0] as char;
    let worktree_status = bytes[1] as char;
    let raw_path = line.get(3..)?.trim();
    if raw_path.is_empty() {
        return None;
    }
    let display_path = raw_path.to_string();
    let normalized_path = raw_path
        .split(" -> ")

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Read the forwarded stderr — it names the exact rule violated; address that specific rule (e.g. remove '~', '^', or ':').
  2. Avoid reserved names: HEAD, refs/heads/*, refs/tags/*, and names matching existing refs.
  3. Run `git check-ref-format --branch <name>` locally to see git's message before submitting.
  4. Sanitize with a slug function and re-validate in a loop until check-ref-format accepts the name.

Example fix

// before
let branch = user_name;  // may contain '~', '^', ':'
validate_branch_name(&repo_root, &branch)?;

// after: iterate until git accepts the name
let mut candidate = user_name;
loop {
    match validate_branch_name(&repo_root, &candidate) {
        Ok(()) => break,
        Err(e) => {
            let next = candidate.chars().map(|c| match c {
                '~'|'^'|':'|' '|'{'|'}' => '-',
                _ => c,
            }).collect::<String>();
            if next == candidate { anyhow::bail!("unfixable branch name: {e}"); }
            candidate = next;
        }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

fn git_accepts_branch(repo_root: &Path, name: &str) -> Result<bool> {
    let out = Command::new("git").arg("-C").arg(repo_root)
        .args(["check-ref-format", "--branch", name]).output()?;
    Ok(out.status.success())
}
// surface git's specific complaint to the user instead of dropping it
if !git_accepts_branch(&repo_root, &branch)? {
    let stderr = Command::new("git").arg("-C").arg(&repo_root)
        .args(["check-ref-format", "--branch", &branch]).output()?;
    let msg = String::from_utf8_lossy(&stderr.stderr).trim().to_string();
    anyhow::bail!("branch rejected: {}", msg);
}

Type guard

fn avoids_reserved_refs(s: &str) -> bool {
    !s.eq_ignore_ascii_case("HEAD")
        && !s.starts_with("refs/heads/")
        && !s.starts_with("refs/tags/")
        && !s.contains('~') && !s.contains('^') && !s.contains(':')
}

Try / catch

match validate_branch_name(&repo_root, &candidate) {
    Ok(()) => Ok(candidate),
    Err(e) => {
        // e.to_string() is git's specific stderr — relay it verbatim to the user
        let next = safe_branch_name(&candidate);
        if next != candidate {
            validate_branch_name(&repo_root, &next)?;
            return Ok(next);
        }
        Err(e)
    }
}

Prevention

When it happens

Trigger: Branch names that git can articulate a specific complaint about: 'refs/heads/..' style errors, locked refs, names that resolve to a different ref namespace, or names that git rejects because they would shadow an existing tag/ref via the --branch resolution path.

Common situations: Trying to name a branch 'HEAD' or 'refs/heads/main' (git complains about reserved names); names that collide with existing refs; version strings like 'v1.2.3' that also exist as tags; branch names containing '~', '^', ':' which check-ref-format flags explicitly.

Related errors


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