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
- 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 '..'.
- Test locally: `git check-ref-format --branch <name>` from your shell to reproduce, then iterate on the name.
- Prefer a deterministic slug derived from the session ID (e.g. lower-case, dash-separated, length-capped).
- 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
- Generate branch names from a known-safe alphabet ([A-Za-z0-9._/-]).
- Always slugify external input (session IDs, ticket titles) before forming a branch name.
- Run `git check-ref-format --branch <name>` in CI before creating branches.
- Forbid leading dashes and trailing dots/slashes in the slugifier.
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
- {stderr}
- Unable to infer ECC repo root from install-state operations
- Project memory .gitignore does not contain the required fail
- selected hunk is already staged
- selected hunk is not staged
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/687e9ae8f20faf76.
Report an issue: GitHub.