Yeachan-Heo/oh-my-codex · error · Error
branch_in_use
branch_in_use
Error message
branch_in_use:${plan.branchName} What it means
Thrown by ensureWorktree when the requested branch name is already checked out in another worktree (git forbids the same branch in two worktrees). The library detects this up front via hasBranchInUse across all known worktrees so the failure is deterministic instead of surfacing as a cryptic git error later.
Source
Thrown at src/team/worktree.ts:441
if (plan.branchName) {
upsertCurrentTaskBaseline(plan.repoRoot, {
branch_name: plan.branchName,
worktree_path: reused.worktreePath,
base_ref: plan.baseRef,
status: 'active',
});
}
return reused;
}
if (existsSync(plan.worktreePath)) {
throw new Error(`worktree_path_conflict:${plan.worktreePath}`);
}
if (plan.branchName && hasBranchInUse(allWorktrees, plan.branchName, plan.worktreePath)) {
throw new Error(`branch_in_use:${plan.branchName}`);
}
if (plan.branchName) {
assertCurrentTaskBranchAvailable(plan.repoRoot, plan.branchName, plan.worktreePath);
}
mkdirSync(dirname(plan.worktreePath), { recursive: true });
const branchAlreadyExisted = plan.branchName ? branchExists(plan.repoRoot, plan.branchName) : false;
const addArgs = ['worktree', 'add'];
if (plan.detached) {
addArgs.push('--detach', plan.worktreePath, plan.baseRef);
} else if (branchAlreadyExisted) {
addArgs.push(plan.worktreePath, plan.branchName as string);
} else {
addArgs.push('-b', plan.branchName as string, plan.worktreePath, plan.baseRef);
}
View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Pick a unique branch name per worktree (append a run id or slug: `task-<id>` instead of `task`)
- Find the holder: `git worktree list` in the repo, then either remove that worktree or reuse it instead of creating a new one
- If the holding worktree is stale: `git worktree remove <path>` (or `git worktree prune`) then retry
- Pass a falsy branchName if the plan does not need a specific branch, letting git create a detached/new ref
Example fix
// before
ensureWorktree({ repoRoot, branchName: 'agent', worktreePath: '.worktrees/a1' });
ensureWorktree({ repoRoot, branchName: 'agent', worktreePath: '.worktrees/a2' }); // branch_in_use:agent
// after
ensureWorktree({ repoRoot, branchName: 'agent-a1', worktreePath: '.worktrees/a1' });
ensureWorktree({ repoRoot, branchName: 'agent-a2', worktreePath: '.worktrees/a2' }); Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from 'node:child_process';
function branchIsFree(repoRoot: string, branch: string): boolean {
const list = execSync('git worktree list --porcelain', { cwd: repoRoot, encoding: 'utf8' });
return !list.split('\n').some((l) => l.startsWith('branch ') && l.trim().endsWith(branch));
} Try / catch
try {
ensureWorktree(plan);
} catch (e) {
if (e instanceof Error && e.message.startsWith('branch_in_use:')) {
plan.branchName = `${plan.branchName}-${Date.now()}`; // uniquify and retry
} else throw e;
} Prevention
- Generate unique branch names per bench/run (suffix with run id)
- Check `git worktree list` before provisioning
- Clean up stale worktrees with git worktree prune in CI setup
When it happens
Trigger: Calling ensureWorktree with plan.branchName set to a branch that another worktree (other than plan.worktreePath itself) currently has checked out. Typical with shared, non-unique branch names like 'main', 'task', or a per-issue branch reused across parallel benches.
Common situations: Parallel agent benches all defaulting to the same branch name; a previous bench still holding the branch checked out in its worktree; re-running a team start after a partial cleanup that removed the directory but not the git worktree registration.
Related errors
- worktree_path_conflict
- (result.stderr || '').trim() || `git ${args.join(' ')} faile
- (result.stderr || '').trim() || `git status failed for ${wor
- autoresearch_reset_requires_clean_worktree
- worktree_not_planned:${workerName}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/b3abf25b616c49ce.
Report an issue: GitHub.