{"record":{"id":"bf252547472664de","repo":"NousResearch/hermes-agent","slug":"gh-pr-create-failed-is-gh-installed-and-authentic","errorCode":null,"errorMessage":"gh pr create failed (is gh installed and authenticated?)","messagePattern":"gh pr create failed \\(is gh installed and authenticated\\?\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/git-review-ops.ts","lineNumber":773,"sourceCode":"    } catch {\n      // A malformed chunk drops its branches; the rest still resolve.\n    }\n  }\n\n  return { ghReady: true, prs }\n}\n\n// Create a PR for the current branch (pushing first so gh has a remote ref),\n// letting gh fill title/body from the commits. Returns the new PR url.\nasync function reviewCreatePr(repoPath, gitBin, ghBin) {\n  const cwd = resolveRequestedPathForIpc(repoPath, { purpose: 'Review create PR' })\n\n  await reviewPush(repoPath, gitBin).catch(() => undefined)\n\n  const created = await runGh(['pr', 'create', '--fill'], cwd, ghBin)\n\n  if (!created.ok) {\n    throw new Error('gh pr create failed (is gh installed and authenticated?)')\n  }\n\n  const url = created.stdout.trim().split('\\n').filter(Boolean).pop() || ''\n\n  return { url }\n}\n\n// Compact working-tree status for the composer coding rail: branch, ahead/behind,\n// per-state change counts, +/- vs HEAD, and a capped changed-file list.\nasync function repoStatus(repoPath, gitBin) {\n  let cwd\n\n  try {\n    cwd = resolveRequestedPathForIpc(repoPath, { purpose: 'Repo status' })\n  } catch {\n    return null\n  }\n","sourceCodeStart":755,"sourceCodeEnd":791,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/electron/git-review-ops.ts#L755-L791","documentation":"Thrown by reviewCreatePr in the desktop app's git-review IPC layer after runGh(['pr','create','--fill']) returned a non-zero exit. The message is a guess: gh either isn't on PATH, isn't authenticated, or refused to create the PR for a repo/branch reason. The preceding reviewPush() failure is deliberately swallowed, so a push failure (no permission, no remote) surfaces here too.","triggerScenarios":"IPC 'Review create PR' action while: gh binary missing from PATH; gh installed but `gh auth status` fails; the branch has no commits differing from the base (--fill finds no commit message and gh errors); the push was rejected (protected branch, no write access) so gh sees no remote ref; no base branch can be inferred on a repo with non-default branch names.","commonSituations":"Corporate machines where gh is not provisioned; fresh clones where the user authenticated git via SSH but never ran `gh auth login`; creating a PR from a branch identical to main; forks where the push went to the fork but gh's default repo resolution points at upstream.","solutions":["Run `gh --version` and `gh auth status` in a terminal; if either fails, install gh and run `gh auth login`.","Verify the branch actually differs from the base: `git log origin/main..HEAD --oneline` (gh pr create --fill needs at least one commit to build title/body from).","Check that reviewPush succeeded — `git push` manually and look for permission/protected-branch errors, since the code swallows push failures.","If gh is installed in a non-standard location, ensure the desktop app inherits a PATH that includes it (launch from a shell or fix the app's environment).","Run `gh pr create --fill` by hand in the repo to see gh's real stderr, which the wrapper discards."],"exampleFix":"// before\nconst created = await runGh(['pr', 'create', '--fill'], cwd, ghBin)\nif (!created.ok) {\n  throw new Error('gh pr create failed (is gh installed and authenticated?)')\n}\n\n// after — surface gh's stderr so users can diagnose\nconst created = await runGh(['pr', 'create', '--fill'], cwd, ghBin)\nif (!created.ok) {\n  const detail = (created.stderr || created.stdout || '').trim().split('\\n').pop()\n  throw new Error(`gh pr create failed (is gh installed and authenticated?)${detail ? `: ${detail}` : ''}`)\n}","handlingStrategy":"try-catch","validationCode":"const { execFileSync } = require('child_process')\nfunction ghReady(ghBin) {\n  try {\n    execFileSync(ghBin || 'gh', ['auth', 'status'], { stdio: 'ignore' })\n    return true\n  } catch {\n    return false\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const { url } = await reviewCreatePr(repoPath, gitBin, ghBin)\n} catch (e) {\n  if (/gh pr create failed/.test(e.message)) {\n    showHint('Run `gh auth login`, verify the branch has commits vs base, then retry.')\n  } else throw e\n}","preventionTips":["Authenticate gh before using PR actions","Ensure the branch has at least one commit the base lacks","Never swallow push failures silently before PR creation"],"tags":["git","github","gh-cli","pull-request","desktop","ipc"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}