{"record":{"id":"b60a4cdd598b42e2","repo":"can1357/oh-my-pi","slug":"could-not-determine-a-clone-url-for-headreposito","errorCode":null,"errorMessage":"Could not determine a clone URL for ${headRepository}.","messagePattern":"Could not determine a clone URL for (.+?)\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/gh-pr-checkout.ts","lineNumber":175,"sourceCode":"\t\treturn {\n\t\t\tname: \"origin\",\n\t\t\turl: originUrl,\n\t\t};\n\t}\n\n\tconst headRepository = requireNonEmpty(data.headRepository?.nameWithOwner, \"head repository\");\n\tconst pullRepo = parsePullRequestUrl(data.url).repo;\n\tconst pullHost = pullRepo ? parseRepoRef(pullRepo).host : undefined;\n\tconst repoSummary = await github.json<GhRepoViewData>(\n\t\trepoRoot,\n\t\t[\"repo\", \"view\", formatRepoRef(pullHost, headRepository), \"--json\", GH_REPO_CLONE_FIELDS.join(\",\")],\n\t\tsignal,\n\t\t{ repoProvided: true },\n\t);\n\tconst originUrl = await repository.remoteUrl(\"origin\", signal);\n\tconst remoteUrl = selectPrCloneUrl(originUrl ?? undefined, repoSummary);\n\tif (!remoteUrl) {\n\t\tthrow new ToolError(`Could not determine a clone URL for ${headRepository}.`);\n\t}\n\n\tconst remotes = new Map<string, string>();\n\tfor (const remoteName of await repository.remoteList(signal)) {\n\t\tconst url = await repository.remoteUrl(remoteName, signal);\n\t\tif (url) remotes.set(remoteName, url);\n\t}\n\tfor (const [remoteName, url] of remotes) {\n\t\tif (url === remoteUrl) {\n\t\t\treturn { name: remoteName, url };\n\t\t}\n\t}\n\n\tconst preferredRemoteName = sanitizeRemoteName(\n\t\tdata.headRepositoryOwner?.login ?? headRepository.split(\"/\")[0] ?? \"fork\",\n\t);\n\tlet remoteName = preferredRemoteName;\n\tlet suffix = 2;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/gh-pr-checkout.ts#L157-L193","documentation":"When checking out a cross-repository PR, the tool queries `gh repo view` for the head repository's clone URLs and picks one via selectPrCloneUrl (preferring HTTPS or SSH based on your origin's scheme). If both `url` and `sshUrl` come back empty from the GitHub CLI, no clone URL can be constructed, so the tool throws this ToolError instead of adding a broken remote.","triggerScenarios":"Calling op pr_checkout for a PR from a fork/head repository where `gh repo view <headRepository> --json url,sshUrl` returns null/empty for both url and sshUrl — e.g. the fork was deleted after the PR was opened, the authenticated token cannot see the head repo (private fork of an org repo), or a GitHub API outage/gh CLI version quirk drops the fields.","commonSituations":"Contributor deleted their fork after opening a PR; PR from a private fork the local token lacks access to; enterprise/hosted GitHub instances where gh returns partial repo JSON; stale gh auth (gh auth login not run or expired scope) causing empty repo view output.","solutions":["Verify the head repository still exists and is visible: `gh repo view <owner>/<name> --json url,sshUrl` — if it errors or returns empty fields, the PR head is gone and only the PR author can restore the fork (or you must fetch the PR refs directly).","Run `gh auth status` and re-authenticate with `gh auth login` (ensure repo scope) so the API returns full repository data.","As a fallback, fetch the PR ref directly: `git fetch origin pull/<N>/head:pr-<N>` and work from that branch instead of the fork remote.","Retry later if GitHub had a transient API failure (check githubstatus.com)."],"exampleFix":"// manual fallback when tool throws\n// before: op pr_checkout 1234  → ToolError: Could not determine a clone URL for contributor/fork\n// after:\ngit fetch origin pull/1234/head:pr-1234\ngit worktree add ../pr-1234-worktree pr-1234","handlingStrategy":"fallback","validationCode":"const view = await github.json<GhRepoViewData>(cwd, [\"repo\",\"view\",headRepo,\"--json\",\"url,sshUrl\"], signal);\nif (!view.url && !view.sshUrl) throw new Error(\"head repo clone URLs unavailable — check fork exists and gh auth\");","typeGuard":"function hasCloneUrl(r: { url?: string|null; sshUrl?: string|null }): r is { url: string; sshUrl?: string|null } {\n  return Boolean(r.url || r.sshUrl);\n}","tryCatchPattern":"try {\n  await op.prCheckout({ prRef });\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes(\"Could not determine a clone URL\")) {\n    await git.fetch([\"origin\", `pull/${prNumber}/head:pr-${prNumber}`]); // fallback to PR ref fetch\n  } else throw err;\n}","preventionTips":["Confirm the fork still exists (`gh repo view owner/fork`) before checking out old PRs.","Keep gh authenticated with repo scope: run `gh auth status` in CI setup.","For private-fork PRs, ensure your token has access to the fork's org.","Have a standing fallback: fetch `pull/N/head` refs directly."],"tags":["git","github-cli","network","fork"],"backgroundTag":"missing-clone-url","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}