affaan-m/ECC · error

branch name is not a valid git ref

Error message

branch name is not a valid git ref

What it means

Thrown by validate_branch_name at ecc2/src/worktree/mod.rs:1491 when `git -C <repo_root> check-ref-format --branch <branch>` fails AND the captured stderr (trimmed) is empty. This is the generic fallback: git refused the branch name but emitted no explanatory text, so the library substitutes a fixed message indicating the name is not a valid git ref. The check-ref-format rules reject names with double dots, trailing dots, leading dashes, control chars, '@{', and other forbidden sequences.

Source

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

    }

    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();

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Sanitize the proposed branch name before calling create_for_session: replace any non-[A-Za-z0-9._/-] character, strip leading dashes and trailing dots, collapse '..'.
  2. Test locally: `git check-ref-format --branch <name>` from your shell to reproduce, then iterate on the name.
  3. Prefer a deterministic slug derived from the session ID (e.g. lower-case, dash-separated, length-capped).
  4. If you must preserve a name that violates ref rules, encode it (URL-encode or hash) and use the encoded form as the branch ref.

Example fix

// before
let branch = format!("feat/{}", raw_user_input);
create_for_session(&session_id, &cfg)?;

// after: slugify before validate_branch_name / create
fn slugify(s: &str) -> String {
    s.chars().map(|c| match c {
        'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '/' => c,
        _ => '-',
    }).collect::<String>()
        .trim_matches(|c: char| c == '-' || c == '.')
        .replace("..", "-")
}
let branch = format!("feat/{}", slugify(&raw_user_input));
Defensive patterns

Strategy: validation

Validate before calling

fn safe_branch_name(raw: &str) -> String {
    let mut s: String = raw.chars().map(|c| match c {
        'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '/' | '.' => c,
        _ => '-',
    }).collect();
    while s.contains("..") { s = s.replace("..", "-"); }
    while s.starts_with('-') || s.starts_with('.') { s.remove(0); }
    while s.ends_with('.') || s.ends_with('/') { s.pop(); }
    s
}
let branch = safe_branch_name(&raw);
validate_branch_name(&repo_root, &branch)?;

Type guard

fn is_valid_branch_name(s: &str) -> bool {
    !s.is_empty()
        && !s.starts_with('-')
        && !s.starts_with('.')
        && !s.ends_with('.')
        && !s.ends_with('/')
        && !s.contains("..")
        && !s.contains("@{")
        && !s.contains(|c: char| !(c.is_ascii_alphanumeric() || "-_./".contains(c)))
}

Try / catch

match validate_branch_name(&repo_root, &candidate) {
    Ok(()) => Ok(candidate),
    Err(e) if e.to_string() == "branch name is not a valid git ref" => {
        let cleaned = safe_branch_name(&candidate);
        validate_branch_name(&repo_root, &cleaned)?;
        Ok(cleaned)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Branch names like '-feature' (leading dash), 'feature..bug' (double dot), 'feature.' (trailing dot), 'feat@{lock' (@{ sequence), names with spaces or control characters, or names containing '\\', '*', '?', '[', or ':'. On some git builds these produce empty stderr on rejection.

Common situations: Auto-generating branch names from session IDs that contain disallowed characters; user-typed branch names with emoji or punctuation; template strings that include '..' for version ranges; names that exceed git's ref-length limits.

Related errors


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