{"record":{"id":"83f6d24cf58bf4fc","repo":"abhigyanpatwari/GitNexus","slug":"source-branch-name-must-not-end-with-lock","errorCode":null,"errorMessage":"${source}: branch name must not end with \".lock\".","messagePattern":"(.+?): branch name must not end with \"\\.lock\"\\.","errorType":"validation","errorClass":"InvalidBranchError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/git-ref.ts","lineNumber":97,"sourceCode":"  // 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('..')) {\n    throw new InvalidBranchError(`${source}: branch name must not contain \"..\".`);\n  }\n  // The remaining `git check-ref-format` rules. Without these the validator\n  // accepted refs git itself refuses (`feature.lock`, `/feature`, `feature/`,\n  // `feature//next`, `@`, `.hidden`), so the failure surfaced later from the\n  // git subprocess instead of here. No real branch can violate them — git\n  // could not have created one — so nothing that works today starts failing.\n  if (trimmed.endsWith('.lock') || trimmed.split('/').some((part) => part.endsWith('.lock'))) {\n    throw new InvalidBranchError(`${source}: branch name must not end with \".lock\".`);\n  }\n  if (trimmed.startsWith('/') || trimmed.endsWith('/')) {\n    throw new InvalidBranchError(`${source}: branch name must not start or end with \"/\".`);\n  }\n  if (trimmed.includes('//')) {\n    throw new InvalidBranchError(`${source}: branch name must not contain consecutive slashes.`);\n  }\n  if (trimmed === '@') {\n    throw new InvalidBranchError(`${source}: branch name must not be the single character \"@\".`);\n  }\n  if (trimmed.includes('@{')) {\n    throw new InvalidBranchError(`${source}: branch name must not contain \"@{\".`);\n  }\n  if (trimmed.endsWith('.') || trimmed.split('/').some((part) => part.startsWith('.'))) {\n    throw new InvalidBranchError(\n      `${source}: branch name must not end with \".\" or have a path component starting with \".\".`,\n    );\n  }","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/git-ref.ts#L79-L115","documentation":"validateBranchName rejects any branch whose name — or any '/'-separated path component — ends with '.lock', matching git's own ref-format rule (a '.lock' suffix collides with git's ref lock files, so git can never create such a ref). The library throws early so the name fails here instead of inside the git subprocess.","triggerScenarios":"Calling validateBranchName with 'feature.lock' or a component ending in .lock like 'wip/experiment.lock'; constructing names by appending extensions programmatically.","commonSituations":"Template or code-generator bugs that append '.lock' or a file extension to branch names; reusing lockfile-style identifiers as branch names; accidental concatenation of a filename with a branch prefix.","solutions":["Remove the '.lock' suffix from the branch name or the offending path component.","Fix the generator/template that appends extensions to branch names.","If '.lock' is semantically meaningful, encode it differently, e.g. 'feature-lock' or 'lock/feature'."],"exampleFix":"// before\nconst branch = `wip/${file}.lock`; // \"wip/index.lock\"\nvalidateBranchName(branch);\n// after\nconst branch = `wip/${file.replace(/\\.lock$/, \"\")}-lock`; // \"wip/index-lock\"\nvalidateBranchName(branch);","handlingStrategy":"validation","validationCode":"function hasLockComponent(name) {\n  return typeof name === \"string\" && name.split(\"/\").some(p => p.endsWith(\".lock\"));\n}\nif (hasLockComponent(branch)) throw new Error(\"branch components must not end with '.lock'\");","typeGuard":"function isLockFreeBranch(v: unknown): v is string {\n  return typeof v === \"string\" && !v.split(\"/\").some(p => p.endsWith(\".lock\"));\n}","tryCatchPattern":"try {\n  validateBranchName(branch, \"generator\");\n} catch (e) {\n  if (e instanceof InvalidBranchError && e.message.includes(\".lock\")) {\n    branch = branch.replace(/(\\.lock)(?=\\/|$)/g, \"-lock\");\n    validateBranchName(branch, \"generator\");\n  } else throw e;\n}","preventionTips":["Never append file extensions to branch names in generators/templates.","Treat '.lock' as reserved at the end of any ref path component.","If lock semantics matter, use a different token like '-lock' or a 'lock/' prefix.","Test generated branch names against git check-ref-format rules."],"tags":["git","branch-name","validation"],"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"}