can1357/oh-my-pi · error · ToolError

Could not determine a clone URL for ${headRepository}.

Error message

Could not determine a clone URL for ${headRepository}.

What it means

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.

Source

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

		return {
			name: "origin",
			url: originUrl,
		};
	}

	const headRepository = requireNonEmpty(data.headRepository?.nameWithOwner, "head repository");
	const pullRepo = parsePullRequestUrl(data.url).repo;
	const pullHost = pullRepo ? parseRepoRef(pullRepo).host : undefined;
	const repoSummary = await github.json<GhRepoViewData>(
		repoRoot,
		["repo", "view", formatRepoRef(pullHost, headRepository), "--json", GH_REPO_CLONE_FIELDS.join(",")],
		signal,
		{ repoProvided: true },
	);
	const originUrl = await repository.remoteUrl("origin", signal);
	const remoteUrl = selectPrCloneUrl(originUrl ?? undefined, repoSummary);
	if (!remoteUrl) {
		throw new ToolError(`Could not determine a clone URL for ${headRepository}.`);
	}

	const remotes = new Map<string, string>();
	for (const remoteName of await repository.remoteList(signal)) {
		const url = await repository.remoteUrl(remoteName, signal);
		if (url) remotes.set(remoteName, url);
	}
	for (const [remoteName, url] of remotes) {
		if (url === remoteUrl) {
			return { name: remoteName, url };
		}
	}

	const preferredRemoteName = sanitizeRemoteName(
		data.headRepositoryOwner?.login ?? headRepository.split("/")[0] ?? "fork",
	);
	let remoteName = preferredRemoteName;
	let suffix = 2;

View on GitHub (pinned to 9690622007)

Solutions

  1. 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).
  2. Run `gh auth status` and re-authenticate with `gh auth login` (ensure repo scope) so the API returns full repository data.
  3. 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.
  4. Retry later if GitHub had a transient API failure (check githubstatus.com).

Example fix

// manual fallback when tool throws
// before: op pr_checkout 1234  → ToolError: Could not determine a clone URL for contributor/fork
// after:
git fetch origin pull/1234/head:pr-1234
git worktree add ../pr-1234-worktree pr-1234
Defensive patterns

Strategy: fallback

Validate before calling

const view = await github.json<GhRepoViewData>(cwd, ["repo","view",headRepo,"--json","url,sshUrl"], signal);
if (!view.url && !view.sshUrl) throw new Error("head repo clone URLs unavailable — check fork exists and gh auth");

Type guard

function hasCloneUrl(r: { url?: string|null; sshUrl?: string|null }): r is { url: string; sshUrl?: string|null } {
  return Boolean(r.url || r.sshUrl);
}

Try / catch

try {
  await op.prCheckout({ prRef });
} catch (err) {
  if (err instanceof ToolError && err.message.includes("Could not determine a clone URL")) {
    await git.fetch(["origin", `pull/${prNumber}/head:pr-${prNumber}`]); // fallback to PR ref fetch
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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