{"record":{"id":"7717b21f03aa03ae","repo":"abhigyanpatwari/GitNexus","slug":"source-branch-name-contains-characters-not-allowed-in-a-git","errorCode":null,"errorMessage":"${source}: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\).","messagePattern":"(.+?): branch name contains characters not allowed in a git ref \\(~ \\^ : \\? \\* \\[ \\\\\\)\\.","errorType":"validation","errorClass":"InvalidBranchError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/git-ref.ts","lineNumber":70,"sourceCode":" * Validate a user-supplied branch name. Returns the trimmed name or throws\n * {@link InvalidBranchError}. Conservative but accepts the shapes real\n * branches use (`feature/foo-bar`, `release/1.2`, `develop`).\n */\nexport function validateBranchName(value: string, source: string): string {\n  const trimmed = value.trim();\n  if (!trimmed) {\n    throw new InvalidBranchError(`${source}: branch name must not be empty.`);\n  }\n  if (trimmed.length > BRANCH_MAX_LENGTH) {\n    throw new InvalidBranchError(`${source}: branch name is too long (max ${BRANCH_MAX_LENGTH}).`);\n  }\n  assertNoHiddenChars(trimmed, source);\n  if (/\\s/.test(trimmed)) {\n    throw new InvalidBranchError(`${source}: branch name must not contain whitespace.`);\n  }\n  // git ref-name rules (subset): reject characters git itself forbids in refs.\n  if (/[~^:?*[\\\\]/.test(trimmed)) {\n    throw new InvalidBranchError(\n      `${source}: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\\\).`,\n    );\n  }\n  if (trimmed.startsWith('-')) {\n    throw new InvalidBranchError(`${source}: branch name must not start with \"-\".`);\n  }\n  // Force-refspec prefix (`git fetch origin +main` / `+refs/heads/main:…`).\n  // Rejected here so neither the CLI nor HTTP can pass a force-update refspec\n  // through as a \"branch\" (#3199 review, defense in depth).\n  if (trimmed.startsWith('+')) {\n    throw new InvalidBranchError(`${source}: branch name must not start with \"+\".`);\n  }\n  // The symbolic ref HEAD (case-sensitive). A repo can have a branch named\n  // `head`; git itself treats only `HEAD` as the current-commit alias.\n  if (trimmed === 'HEAD') {\n    throw new InvalidBranchError(`${source}: branch name must not be \"HEAD\".`);\n  }\n  if (trimmed.includes('..')) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/git-ref.ts#L52-L88","documentation":"validateBranchName enforces a subset of git's ref-name rules and throws InvalidBranchError '<source>: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\\\).' when the name matches /[~^:?*[\\\\]/. Git itself forbids these characters in refs, so any such name would fail at git level anyway; the library rejects it early with a clear message.","triggerScenarios":"Calling validateBranchName with any of ~ ^ : ? * [ or \\\\ in the value — e.g. 'feature:v2', 'release~1', 'fix*test', a Windows path fragment like 'feature\\\\foo', or glob-like names 'bug?[0-9]'.","commonSituations":"Deriving branch names from file paths on Windows (backslashes); using colon-separated prefixes like 'user:topic'; wildcard patterns intended for matching being passed as literal names; date strings with colons from toISOString-style formatting.","solutions":["Remove or replace the forbidden characters (~ ^ : ? * [ \\\\) with safe ones such as '-' or '/'.","Convert path separators to '/' (or '-') when deriving names from paths: value.replace(/\\\\+/g, '-').","Sanitize generated names (e.g. timestamps '2026-09-15T10:00:00Z' → '2026-09-15-100000z') before validation.","Adopt a naming convention of lowercase alphanumerics, '-', '_', and '/' only."],"exampleFix":"// before\nconst branch = `work/${new Date().toISOString()}`; // contains ':'\nvalidateBranchName(branch, 'worktree');\n// after\nconst branch = `work/${new Date().toISOString().replace(/[:]/g, '-')}`;\nvalidateBranchName(branch, 'worktree');","handlingStrategy":"validation","validationCode":"if (/[~^:?*[\\\\]/.test(name)) {\n  name = name.replace(/[~^:?*[\\\\]/g, '-');\n}","typeGuard":"const isGitRefSafe = (v: string): boolean => !/[~^:?*[\\\\]/.test(v);","tryCatchPattern":"try {\n  branch = validateBranchName(input, 'worktree');\n} catch (e) {\n  if (e instanceof InvalidBranchError && /not allowed in a git ref/.test(e.message)) {\n    branch = validateBranchName(input.replace(/[~^:?*[\\\\]/g, '-'), 'worktree');\n  } else throw e;\n}","preventionTips":["Restrict generated names to [A-Za-z0-9/_-] only.","Convert path separators (especially Windows backslashes) to '-' or '/' when deriving names.","Format timestamps for refs without colons (e.g. 2026-09-15-101500).","Never pass glob/wildcard patterns as literal branch names."],"tags":["git","branch-name","validation","refname-rules"],"backgroundTag":"invalid-identifier-format","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}