{"record":{"id":"d0fbdb98dd76b317","repo":"can1357/oh-my-pi","slug":"could-not-find-an-unused-worktree-path-under-bas","errorCode":null,"errorMessage":"could not find an unused worktree path under ${basePath} (tried ${WORKTREE_PATH_MAX_SUFFIX} suffixes)","messagePattern":"could not find an unused worktree path under (.+?) \\(tried (.+?) suffixes\\)","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/gh-pr-checkout.ts","lineNumber":113,"sourceCode":"export async function resolveAvailableWorktreePath(\n\tbasePath: string,\n\texistingWorktrees: VcsWorktreeEntry[],\n): Promise<string> {\n\tconst registered = new Set(existingWorktrees.map(entry => path.resolve(entry.path)));\n\tfor (let attempt = 0; attempt < WORKTREE_PATH_MAX_SUFFIX; attempt += 1) {\n\t\tconst candidate = attempt === 0 ? basePath : `${basePath}-${attempt + 1}`;\n\t\tconst normalized = path.resolve(candidate);\n\t\tif (registered.has(normalized)) continue;\n\t\ttry {\n\t\t\tawait fs.stat(normalized);\n\t\t} catch (error) {\n\t\t\tif (isEnoent(error)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\tthrow new ToolError(\n\t\t`could not find an unused worktree path under ${basePath} (tried ${WORKTREE_PATH_MAX_SUFFIX} suffixes)`,\n\t);\n}\n\nexport function selectPrCloneUrl(originUrl: string | undefined, repo: Pick<GhRepoViewData, \"url\" | \"sshUrl\">): string {\n\tif (originUrl?.startsWith(\"http://\") || originUrl?.startsWith(\"https://\")) {\n\t\treturn normalizeOptionalString(repo.url) ?? normalizeOptionalString(repo.sshUrl) ?? \"\";\n\t}\n\n\treturn normalizeOptionalString(repo.sshUrl) ?? normalizeOptionalString(repo.url) ?? \"\";\n}\n\nexport async function getRemoteUrls(repoRoot: string, signal?: AbortSignal): Promise<Map<string, string>> {\n\tconst repo = vcs.requireGit(repoRoot);\n\tconst remotes = await repo.remoteList(signal);\n\tconst urls = new Map<string, string>();\n\tfor (const remoteName of remotes) {\n\t\tconst remoteUrl = await repo.remoteUrl(remoteName, signal);","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/gh-pr-checkout.ts#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before: all candidates exist\n$ git worktree list  # many stale entries pr-12, pr-12-2, ...\n# after\n$ git worktree remove ../project-pr-12 && git worktree prune","handlingStrategy":"try-catch","validationCode":"import * as fs from \"node:fs\";\nfunction worktreePathAvailable(basePath) {\n  return !fs.existsSync(basePath) && !fs.existsSync(`${basePath}-2`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await checkoutPullRequest({ cwd, pr });\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes(\"unused worktree path\")) {\n    // prune stale worktrees then retry once\n    await $`git worktree prune`.cwd(cwd);\n  } else throw err;\n}","preventionTips":["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."],"tags":["git","worktree","filesystem","exhaustion"],"backgroundTag":"worktree-path-exhausted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}