can1357/oh-my-pi · error · ToolError
could not find an unused worktree path under ${basePath} (tr
Error message
could not find an unused worktree path under ${basePath} (tried ${WORKTREE_PATH_MAX_SUFFIX} suffixes) What it means
resolveAvailableWorktreePath probes candidate paths (basePath, basePath-2, ... up to WORKTREE_PATH_MAX_SUFFIX) looking for a non-existent location for the new worktree. If every candidate exists (or stat errors other than ENOENT persist), it throws this ToolError after exhausting all suffixes.
Source
Thrown at packages/coding-agent/src/tools/gh-pr-checkout.ts:113
export async function resolveAvailableWorktreePath(
basePath: string,
existingWorktrees: VcsWorktreeEntry[],
): Promise<string> {
const registered = new Set(existingWorktrees.map(entry => path.resolve(entry.path)));
for (let attempt = 0; attempt < WORKTREE_PATH_MAX_SUFFIX; attempt += 1) {
const candidate = attempt === 0 ? basePath : `${basePath}-${attempt + 1}`;
const normalized = path.resolve(candidate);
if (registered.has(normalized)) continue;
try {
await fs.stat(normalized);
} catch (error) {
if (isEnoent(error)) {
return candidate;
}
throw error;
}
}
throw new ToolError(
`could not find an unused worktree path under ${basePath} (tried ${WORKTREE_PATH_MAX_SUFFIX} suffixes)`,
);
}
export function selectPrCloneUrl(originUrl: string | undefined, repo: Pick<GhRepoViewData, "url" | "sshUrl">): string {
if (originUrl?.startsWith("http://") || originUrl?.startsWith("https://")) {
return normalizeOptionalString(repo.url) ?? normalizeOptionalString(repo.sshUrl) ?? "";
}
return normalizeOptionalString(repo.sshUrl) ?? normalizeOptionalString(repo.url) ?? "";
}
export async function getRemoteUrls(repoRoot: string, signal?: AbortSignal): Promise<Map<string, string>> {
const repo = vcs.requireGit(repoRoot);
const remotes = await repo.remoteList(signal);
const urls = new Map<string, string>();
for (const remoteName of remotes) {
const remoteUrl = await repo.remoteUrl(remoteName, signal);View on GitHub (pinned to 9690622007)
Solutions
- Clean up stale worktrees: `git worktree list` then `git worktree remove <path>` (or delete leftover directories) and retry.
- Free/rename the occupied candidate paths under basePath so a suffix becomes available.
- Raise WORKTREE_PATH_MAX_SUFFIX or use a different base directory if this is a high-churn environment.
Example fix
# before: all candidates exist $ git worktree list # many stale entries pr-12, pr-12-2, ... # after $ git worktree remove ../project-pr-12 && git worktree prune
Defensive patterns
Strategy: try-catch
Validate before calling
import * as fs from "node:fs";
function worktreePathAvailable(basePath) {
return !fs.existsSync(basePath) && !fs.existsSync(`${basePath}-2`);
} Try / catch
try {
await checkoutPullRequest({ cwd, pr });
} catch (err) {
if (err instanceof ToolError && err.message.includes("unused worktree path")) {
// prune stale worktrees then retry once
await $`git worktree prune`.cwd(cwd);
} else throw err;
} Prevention
- Periodically run `git worktree prune` and remove finished PR worktrees.
- Use a dedicated, cleaned scratch directory as the worktree base.
- Monitor disk/paths for accumulation of suffixed worktree directories.
When it happens
Trigger: checkoutPullRequest called when a project directory accumulates many existing worktrees/dirs with the same base name — e.g. repeatedly checking out PRs that map to the same base path until all suffixed names are taken.
Common situations: Long-lived machine where prior PR checkouts were never cleaned up; leftover directories from crashed runs; a base path collision with an existing project folder name.
Related errors
- not a repository: {path}
- Security scans require a Git repository: ${request.cwd}
- Isolated subagent execution could not be prepared: ${message
- GitCommandError: git command failed (nonzero exit)
- GitCommandError: git worktree prune failed (nonzero exit)
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d0fbdb98dd76b317.
Report an issue: GitHub.