{"record":{"id":"2ac90d4726e87b21","repo":"NousResearch/hermes-agent","slug":"branch-name-is-required","errorCode":null,"errorMessage":"Branch name is required.","messagePattern":"Branch name is required\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/git-worktree-ops.ts","lineNumber":249,"sourceCode":"}\n\nfunction uniqueDir(base) {\n  let dir = base\n  let n = 1\n\n  while (fs.existsSync(dir)) {\n    n += 1\n    dir = `${base}-${n}`\n  }\n\n  return dir\n}\n\nasync function addExistingBranchWorktree(gitBin, root, name) {\n  const requested = sanitizeBranch(name)\n\n  if (!requested) {\n    throw new Error('Branch name is required.')\n  }\n\n  // \"origin/feature\" is a remote-tracking ref and not a branch that git can\n  // check out. `git worktree add <dir> origin/feature` detaches HEAD. Make a\n  // local branch with the same short name that tracks the remote ref. This is\n  // what `git switch feature` does for a branch on exactly one remote.\n  const remote = await remoteOfRef(gitBin, root, requested)\n  const branch = remote ? requested.slice(remote.length + 1) : requested\n\n  if (!remote && branch === (await defaultBranch(gitBin, root))) {\n    await runGit(gitBin, ['switch', branch], root)\n\n    return { path: root, branch, repoRoot: root }\n  }\n\n  const dir = uniqueDir(path.join(root, '.worktrees', slugify(branch)))\n\n  if (remote) {","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/electron/git-worktree-ops.ts#L231-L267","documentation":"Thrown by addExistingBranchWorktree when sanitizeBranch(name) returns an empty string. sanitizeBranch strips characters invalid in git branch names, so the guard fires when the caller passes an empty, whitespace-only, or entirely-invalid branch name (e.g. '..' or '..only-punctuation') to the 'add existing branch worktree' IPC.","triggerScenarios":"IPC call to add a worktree for an existing branch with branch='' or undefined; a UI text field submitting before the user typed anything; a branch name composed solely of characters sanitizeBranch removes (leading/trailing dots, spaces, ~, ^, :, ?, *, [, \\).","commonSituations":"A form dialog whose submit button isn't disabled on empty input; programmatically forwarding a selected value from a list where nothing was selected (null coerced to string).","solutions":["Pass a non-empty branch name that survives sanitization (letters, digits, '-', '_', '/').","Disable the UI's confirm/add button while the branch-name field is blank.","If the name comes from a list selection, guard against null/undefined before calling the IPC."],"exampleFix":"// before\nawait addExistingBranchWorktree(gitBin, root, name) // name may be ''\n\n// after\nconst requested = sanitizeBranch(name || '')\nif (!requested) throw new Error('Branch name is required.')\nawait addExistingBranchWorktree(gitBin, root, requested)","handlingStrategy":"validation","validationCode":"const requested = sanitizeBranch(String(name || '').trim())\nif (!requested) {\n  return showDialog('Enter a branch name before adding the worktree.')\n}","typeGuard":"function isNonEmptyBranchName(name) {\n  return typeof name === 'string' && sanitizeBranch(name) !== ''\n}","tryCatchPattern":null,"preventionTips":["Disable submit while the branch field is empty","Guard null/undefined list selections before IPC","Test sanitizeBranch against your allowed name alphabet"],"tags":["git","worktree","branch","validation","desktop","ipc"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}