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

branch name is not a valid git ref

Error message

branch name is not a valid git ref

What it means

`validate_branch_name` runs git's own ref-name check and bails with this generic message when the check fails and git printed no stderr. It means the supplied branch name violates git ref naming rules (e.g. contains spaces, '..', starts with '-', ends with '.lock', or includes control characters).

Solutions

  1. Sanitize the name: replace spaces and invalid characters with '-', strip leading '-' and trailing '.lock'/'.'
  2. Validate before calling using 'git check-ref-format --branch <name>' and surface its stderr
  3. Keep names to [A-Za-z0-9._/-] without '..' or '@{' sequences
  4. If the name comes from user input, apply a slugify/kebab-case step at the boundary

Example fix

// before: raw user input
let branch = user_input.trim();
validate_branch_name(&root, branch)?;
// after: normalize to a safe ref name
let branch: String = user_input
    .trim()
    .to_lowercase()
    .chars()
    .map(|c| if c.is_ascii_alphanumeric() || matches!(c, '/' | '-' | '_' | '.') { c } else { '-' })
    .collect();
let branch = branch.trim_matches(|c| c == '-' || c == '.').to_string();
validate_branch_name(&root, &branch)?;
Defensive patterns

Strategy: validation

Validate before calling

let valid = Command::new("git")
    .args(["check-ref-format", "--branch", name])
    .output()
    .map(|o| o.status.success())
    .unwrap_or(false);

Type guard

fn is_safe_branch_name(name: &str) -> bool {
    !name.is_empty()
        && name.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '/' | '-' | '_' | '.'))
        && !name.contains("..")
        && !name.contains("@{")
        && !name.starts_with('-')
        && !name.ends_with(".lock")
}

Try / catch

match create_branch(&root, name) {
    Ok(b) => b,
    Err(e) if e.to_string().contains("not a valid git ref") => {
        eprintln!("sanitize name '{name}' (spaces/.. /.lock are forbidden)");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Creating or renaming a branch with a name git rejects but whose rejection message is empty — commonly names with forbidden sequences like 'a..b', 'a b', '@{', or empty/whitespace names.

Common situations: Branch name derived from a free-text prompt, ticket title, or AI-generated label that contains spaces or invalid characters; trailing slashes; names ending in '.lock' or '.".',

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/687e9ae8f20faf76. Report an issue: GitHub.

Appendix: 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 8321021c54)