can1357/oh-my-pi · error · ToolError

local branch ${localBranch} already exists at ${formatShortS

Error message

local branch ${localBranch} already exists at ${formatShortSha(existingOid ?? undefined) ?? existingOid ?? "unknown commit"}; pass force=true to reset it

What it means

When checking out a PR, the tool wants to create local branch <localBranch>. If that branch already exists and points at a different commit than the PR head (headRefOid), creating it would either fail or silently diverge, so without force=true the tool throws and tells you the existing commit and how to override.

Source

Thrown at packages/coding-agent/src/tools/gh-pr-checkout.ts:451

			const existingWorktree = existingWorktrees.find(entry => entry.branch === toLocalBranchRef(localBranch));

			const remote = await ensurePrRemoteWithRepo(repoRoot, data, repository, signal);
			await repository.fetch(
				remote.name,
				`refs/heads/${headRefName}`,
				`refs/remotes/${remote.name}/${headRefName}`,
				PR_FETCH_TIMEOUT_MS,
				signal,
			);

			if (!existingWorktree) {
				const localBranchRef = toLocalBranchRef(localBranch);
				const localBranchExists = await repository.refExists(localBranchRef, signal);
				if (localBranchExists) {
					const existingOid = await repository.resolveRef(localBranchRef, signal);
					if (existingOid !== headRefOid) {
						if (!force) {
							throw new ToolError(
								`local branch ${localBranch} already exists at ${formatShortSha(existingOid ?? undefined) ?? existingOid ?? "unknown commit"}; pass force=true to reset it`,
							);
						}

						await repository.createBranch(
							localBranch,
							`refs/remotes/${remote.name}/${headRefName}`,
							true,
							signal,
						);
					}
				} else {
					await repository.createBranch(localBranch, `refs/remotes/${remote.name}/${headRefName}`, false, signal);
				}
			}

			const configPrefix = `branch.${localBranch}.`;
			await repository.configSet(`${configPrefix}remote`, remote.name, signal);

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-run the checkout with force=true (force option) to reset the existing local branch to the PR head commit — but first confirm you have no unpushed local commits on that branch you need.
  2. If the local branch has your own work, rename it first: `git branch -m <localBranch> <localBranch>-backup`, then check out the PR again.
  3. Compare the commits before forcing: `git log <localBranch>..HEAD` / check the existing SHA from the message to decide whether resetting loses anything.

Example fix

// before: second checkout of PR 123 after new upstream commits
// ToolError: local branch pr/123 already exists at abc1234; pass force=true
// after
op pr_checkout 1234 force=true   // resets pr/123 to new head
git branch -m pr/123 pr/123-old  // ...or preserve local work first
Defensive patterns

Strategy: validation

Validate before calling

const branchRef = `refs/heads/${localBranch}`;
if (await repo.refExists(branchRef)) {
  const oid = await repo.resolveRef(branchRef);
  if (oid !== prHeadOid && !hasUnpushedWork(branchRef)) {
    // safe to force-reset
  }
}

Try / catch

try {
  await op.prCheckout({ prRef, force: false });
} catch (err) {
  if (err instanceof ToolError && err.message.includes("already exists")) {
    await git.branch(["-m", localBranch, `${localBranch}-backup`]); // preserve, then retry
    await op.prCheckout({ prRef });
  } else throw err;
}

Prevention

When it happens

Trigger: Running op pr_checkout twice for the same PR after the PR gained new commits (local branch still at old head); a pre-existing branch with the same conventional name (e.g. `pr/123` or the head branch name) from another source; a stale checkout from a previous session.

Common situations: Re-checking out an actively updated PR; name collision with a user's own branch; reusing a repo where someone branched locally with the same name.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/4d37b78c035db198. Report an issue: GitHub.