stablyai/orca · error
Invalid branch name
Error message
Invalid branch name
What it means
Thrown at the top of forceDeleteLocalBranch when branchName is falsy (empty string, undefined, null) OR contains a NUL byte (`\0`). The NUL check is an argv-injection guard: git uses NUL as a record separator in porcelain output and a NUL in a branch name could smuggle additional ref arguments into `update-ref`. This is a programmer-error guard, not a recoverable runtime condition.
Source
Thrown at src/main/git/worktree.ts:1385
return false
}
await forceDeleteLocalBranch(repoPath, branchName, branchHead, (args, cwd) =>
gitExecFileAsync(args, gitExecOptions(cwd, options))
)
return true
}
export async function forceDeleteLocalBranch(
repoPath: string,
branchName: string,
expectedHead: string,
runGit: (args: string[], cwd: string) => Promise<{ stdout: string; stderr: string }> = (
args,
cwd
) => gitExecFileAsync(args, { cwd })
): Promise<void> {
if (!branchName || branchName.includes('\0')) {
throw new Error('Invalid branch name')
}
if (!expectedHead) {
throw new Error(
`Cannot force-delete local branch "${branchName}" without the commit Git preserved.`
)
}
if (await isLocalBranchCheckedOut(repoPath, branchName, runGit)) {
throw new Error(`Local branch "${branchName}" is checked out in another worktree.`)
}
// Why: stale toast actions must not delete a branch that moved; `update-ref -d` deletes only if the ref still == expectedHead.
try {
await runGit(['update-ref', '-d', `refs/heads/${branchName}`, expectedHead], repoPath)
} catch {
throw new Error(
`Local branch "${branchName}" changed after the workspace was deleted. Review it before deleting it.`
)
}
if (await isLocalBranchCheckedOut(repoPath, branchName, runGit)) {View on GitHub (pinned to 1136503c6a)
Solutions
- Inspect the call site: ensure branchName is always a non-empty string before invoking forceDeleteLocalBranch.
- If the value is coming from a serialized toast action, validate and discard the action when branchName is empty rather than calling through.
- Sanitize ref names at the trust boundary — reject any containing NUL, whitespace, or `..`/`~`/`^`/`:` per git-check-ref-format before they reach this function.
Example fix
// before
await forceDeleteLocalBranch(repoPath, maybeBranch, head)
// after
if (!maybeBranch || maybeBranch.includes('\0')) {
discardStaleToast()
return
}
await forceDeleteLocalBranch(repoPath, maybeBranch, head) Defensive patterns
Strategy: validation
Validate before calling
function isValidBranchNameForDelete(name: unknown): name is string {
return typeof name === 'string' && name.length > 0 && !name.includes('\0')
} Type guard
function isValidBranchNameForDelete(name: unknown): name is string {
return typeof name === 'string' && name.length > 0 && !name.includes('\0')
} Prevention
- Validate branch names at the UI/API trust boundary, not just at the git call.
- Discard stale toast actions whose payload is missing a branch name.
- Reject ref names failing git-check-ref-format before they reach deletion.
When it happens
Trigger: A stale toast action firing after the branch name was cleared from UI state; a serialized action whose branch field was never populated; a malicious or malformed ref name reaching the function via a crafted remote; testing code that passes undefined by mistake.
Common situations: UI 'delete branch' toast surviving a workspace reload that nulled the branch field; a race where the worktree is removed before the branch-delete action captures its name; fuzzed/malicious input attempting argument injection.
Related errors
- Cannot force-delete local branch "${branchName}" without the
- Pull request fetch remote must not start with "-".
- ${name} must be a positive integer, received ${value}
- no benchmark file exists at both HEAD and HEAD~1 in this che
- No worktrees on environment ${envName}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/a0a6821eecf90166.
Report an issue: GitHub.