{"record":{"id":"1803808d7b43da04","repo":"affaan-m/ECC","slug":"stderr","errorCode":null,"errorMessage":"{stderr}","messagePattern":"\\{stderr\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":1493,"sourceCode":"    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();\n    let normalized_path = raw_path\n        .split(\" -> \")","sourceCodeStart":1475,"sourceCodeEnd":1511,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L1475-L1511","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the forwarded stderr — it names the exact rule violated; address that specific rule (e.g. remove '~', '^', or ':').","Avoid reserved names: HEAD, refs/heads/*, refs/tags/*, and names matching existing refs.","Run `git check-ref-format --branch <name>` locally to see git's message before submitting.","Sanitize with a slug function and re-validate in a loop until check-ref-format accepts the name."],"exampleFix":"// before\nlet branch = user_name;  // may contain '~', '^', ':'\nvalidate_branch_name(&repo_root, &branch)?;\n\n// after: iterate until git accepts the name\nlet mut candidate = user_name;\nloop {\n    match validate_branch_name(&repo_root, &candidate) {\n        Ok(()) => break,\n        Err(e) => {\n            let next = candidate.chars().map(|c| match c {\n                '~'|'^'|':'|' '|'{'|'}' => '-',\n                _ => c,\n            }).collect::<String>();\n            if next == candidate { anyhow::bail!(\"unfixable branch name: {e}\"); }\n            candidate = next;\n        }\n    }\n}","handlingStrategy":"validation","validationCode":"fn git_accepts_branch(repo_root: &Path, name: &str) -> Result<bool> {\n    let out = Command::new(\"git\").arg(\"-C\").arg(repo_root)\n        .args([\"check-ref-format\", \"--branch\", name]).output()?;\n    Ok(out.status.success())\n}\n// surface git's specific complaint to the user instead of dropping it\nif !git_accepts_branch(&repo_root, &branch)? {\n    let stderr = Command::new(\"git\").arg(\"-C\").arg(&repo_root)\n        .args([\"check-ref-format\", \"--branch\", &branch]).output()?;\n    let msg = String::from_utf8_lossy(&stderr.stderr).trim().to_string();\n    anyhow::bail!(\"branch rejected: {}\", msg);\n}","typeGuard":"fn avoids_reserved_refs(s: &str) -> bool {\n    !s.eq_ignore_ascii_case(\"HEAD\")\n        && !s.starts_with(\"refs/heads/\")\n        && !s.starts_with(\"refs/tags/\")\n        && !s.contains('~') && !s.contains('^') && !s.contains(':')\n}","tryCatchPattern":"match validate_branch_name(&repo_root, &candidate) {\n    Ok(()) => Ok(candidate),\n    Err(e) => {\n        // e.to_string() is git's specific stderr — relay it verbatim to the user\n        let next = safe_branch_name(&candidate);\n        if next != candidate {\n            validate_branch_name(&repo_root, &next)?;\n            return Ok(next);\n        }\n        Err(e)\n    }\n}","preventionTips":["Run check-ref-format in CI for every branch created from external input.","Strip git-significant punctuation ('~', '^', ':', '@{', '..') in the slugifier.","Avoid branch names that collide with tags or remote-tracking refs.","Show git's verbatim stderr to the user so they can fix the specific rule violated."],"tags":["git","branch","validation","ref-format","diagnostic"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}