{"record":{"id":"5a700071b0baae77","repo":"can1357/oh-my-pi","slug":"github-cli-did-not-return-a-pull-request-number","errorCode":null,"errorMessage":"GitHub CLI did not return a pull request number.","messagePattern":"GitHub CLI did not return a pull request number\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/gh-pr-checkout.ts","lineNumber":410,"sourceCode":"\tsession: ToolSession,\n\tsignal: AbortSignal | undefined,\n\toptions: PrCheckoutOptions,\n): Promise<PrCheckoutOutcome> {\n\tconst { prRef, repo, force } = options;\n\tif (prRef?.startsWith(\"-\")) {\n\t\tthrow new ToolError(`invalid PR identifier: ${prRef}. Pass a PR number, URL, or branch name.`);\n\t}\n\tconst args = [\"pr\", \"view\"];\n\tif (prRef) args.push(prRef);\n\tappendRepoFlag(args, repo, prRef);\n\targs.push(\"--json\", GH_PR_CHECKOUT_FIELDS.join(\",\"));\n\n\tconst data = await github.json<GhPrViewData>(session.cwd, args, signal, {\n\t\trepoProvided: Boolean(repo),\n\t});\n\tconst prNumber = data.number;\n\tif (typeof prNumber !== \"number\") {\n\t\tthrow new ToolError(\"GitHub CLI did not return a pull request number.\");\n\t}\n\n\tconst headRefName = requireNonEmpty(data.headRefName, \"head branch\");\n\tconst headRefOid = requireNonEmpty(data.headRefOid, \"head commit\");\n\tconst repoRoot = await requireGitRepoRoot(session.cwd, signal);\n\tconst primaryRepoRoot = await requirePrimaryGitRepoRoot(repoRoot, signal);\n\tconst localBranch = `pr-${prNumber}`;\n\tconst worktreePath = getWorktreeDir(`${prNumber}-${hashPath(primaryRepoRoot)}`);\n\n\t// Every git mutation against `repoRoot` from here on must run under the\n\t// per-repo lock. Worktrees of the same primary repo share `.git/config`,\n\t// `commit-graph` chain, `packed-refs`, and worktree metadata files — git\n\t// uses O_EXCL lock files for each, with no waiter. Concurrent in-process\n\t// callers (e.g. parallel `pr_checkout` calls) would otherwise lose lock\n\t// races and surface \"could not lock config file\" / \"Another git process\n\t// seems to be running\" errors. The gh API call above stays outside the\n\t// lock so multiple checkouts can fetch PR metadata in parallel.\n\treturn withRepoLock(","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/gh-pr-checkout.ts#L392-L428","documentation":"After running `gh pr view --json ...`, the tool expects the `number` field to be a number. If gh returns JSON without a numeric `number` (missing, null, or wrong type), the response is unusable for building branch names and push metadata, so the tool throws. This normally indicates a gh CLI/API malfunction rather than user input error, since a successful pr view always includes number.","triggerScenarios":"gh CLI emitting error JSON or an unexpected shape (authentication failure returning a non-standard payload, GitHub API partial outage, proxy/captive portal returning HTML-adjacent JSON wrappers), a drastically old gh version lacking the requested --json fields, or a wrapper script shadowing `gh` that prints extra output the JSON parser misreads.","commonSituations":"Expired/insufficient gh auth token; corporate proxy intercepting api.github.com; gh version predating `pr view --json` field support; GH_HOST pointing at a non-GitHub endpoint.","solutions":["Run the same command manually: `gh pr view <ref> --json number,headRefName,headRefOid` — inspect what it actually returns.","Check `gh auth status` and re-login (`gh auth login`) if the token is expired or missing scopes.","Upgrade the GitHub CLI (`gh --version`, then update) — old versions may omit fields from the --json output.","Verify GH_HOST/proxy environment variables point at real GitHub and that no wrapper intercepts `gh` (`which gh`)."],"exampleFix":"// before: gh returns {\"message\":\"Bad credentials\"}-shaped output → tool throws\n// after: fix auth then retry\ngh auth login\nop pr_checkout 1234","handlingStrategy":"retry","validationCode":"const out = Bun.$`gh pr view ${ref} --json number`.quiet().nothrow();\nif (!out.exitCode || !/^\\s*\\{/.test(await out.text())) throw new Error(\"gh pr view returned unexpected output — check auth/network\");","typeGuard":"function hasPrNumber(d: unknown): d is { number: number } {\n  return typeof d === \"object\" && d !== null && typeof (d as { number?: unknown }).number === \"number\";\n}","tryCatchPattern":"try {\n  await op.prCheckout({ prRef });\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes(\"did not return a pull request number\")) {\n    await Bun.sleep(2000); // transient API/proxy glitch — retry once\n    await op.prCheckout({ prRef });\n  } else throw err;\n}","preventionTips":["Run `gh auth status` before automated checkout runs.","Keep the GitHub CLI up to date (`gh --version`).","Check GH_HOST and proxy env vars point at real GitHub.","Avoid wrapper scripts around `gh` that emit extra output."],"tags":["github-cli","api","auth","network"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}