{"record":{"id":"687e9ae8f20faf76","repo":"affaan-m/ECC","slug":"branch-name-is-not-a-valid-git-ref","errorCode":null,"errorMessage":"branch name is not a valid git ref","messagePattern":"branch name is not a valid git ref","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":1491,"sourceCode":"    }\n\n    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())\n}\n\nfn validate_branch_name(repo_root: &Path, branch: &str) -> Result<()> {\n    let output = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(repo_root)\n        .args([\"check-ref-format\", \"--branch\", branch])\n        .output()\n        .context(\"Failed to validate worktree branch name\")?;\n\n    if output.status.success() {\n        Ok(())\n    } else {\n        let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();\n        if stderr.is_empty() {\n            anyhow::bail!(\"branch name is not a valid git ref\");\n        } else {\n            anyhow::bail!(\"{stderr}\");\n        }\n    }\n}\n\nfn parse_git_status_entry(line: &str) -> Option<GitStatusEntry> {\n    if line.len() < 4 {\n        return None;\n    }\n    let bytes = line.as_bytes();\n    let index_status = bytes[0] as char;\n    let worktree_status = bytes[1] as char;\n    let raw_path = line.get(3..)?.trim();\n    if raw_path.is_empty() {\n        return None;\n    }\n    let display_path = raw_path.to_string();","sourceCodeStart":1473,"sourceCodeEnd":1509,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L1473-L1509","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet branch = format!(\"feat/{}\", raw_user_input);\ncreate_for_session(&session_id, &cfg)?;\n\n// after: slugify before validate_branch_name / create\nfn slugify(s: &str) -> String {\n    s.chars().map(|c| match c {\n        'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '/' => c,\n        _ => '-',\n    }).collect::<String>()\n        .trim_matches(|c: char| c == '-' || c == '.')\n        .replace(\"..\", \"-\")\n}\nlet branch = format!(\"feat/{}\", slugify(&raw_user_input));","handlingStrategy":"validation","validationCode":"fn safe_branch_name(raw: &str) -> String {\n    let mut s: String = raw.chars().map(|c| match c {\n        'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '/' | '.' => c,\n        _ => '-',\n    }).collect();\n    while s.contains(\"..\") { s = s.replace(\"..\", \"-\"); }\n    while s.starts_with('-') || s.starts_with('.') { s.remove(0); }\n    while s.ends_with('.') || s.ends_with('/') { s.pop(); }\n    s\n}\nlet branch = safe_branch_name(&raw);\nvalidate_branch_name(&repo_root, &branch)?;","typeGuard":"fn is_valid_branch_name(s: &str) -> bool {\n    !s.is_empty()\n        && !s.starts_with('-')\n        && !s.starts_with('.')\n        && !s.ends_with('.')\n        && !s.ends_with('/')\n        && !s.contains(\"..\")\n        && !s.contains(\"@{\")\n        && !s.contains(|c: char| !(c.is_ascii_alphanumeric() || \"-_./\".contains(c)))\n}","tryCatchPattern":"match validate_branch_name(&repo_root, &candidate) {\n    Ok(()) => Ok(candidate),\n    Err(e) if e.to_string() == \"branch name is not a valid git ref\" => {\n        let cleaned = safe_branch_name(&candidate);\n        validate_branch_name(&repo_root, &cleaned)?;\n        Ok(cleaned)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["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."],"tags":["git","branch","validation","ref-format"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}