Graphify-Labs/graphify · error · RuntimeError
gh CLI not found or not authenticated. Run: gh auth login
Error message
gh CLI not found or not authenticated. Run: gh auth login
What it means
RuntimeError raised when the `gh` helper returns None from a PR-list call, meaning the GitHub CLI binary is missing or not authenticated. fetch_prs builds a `gh pr list --json ...` invocation (prs.py:210-220); _gh returns None on spawn/lookup failure or auth errors, and this message tells the user to run `gh auth login`.
Source
Thrown at graphify/prs.py:210
return "PENDING"
if "SUCCESS" in conclusions:
return "SUCCESS"
return "NONE"
def fetch_prs(repo: str | None = None, base: str | None = None, limit: int = 50) -> list[PRInfo]:
resolved_base = base or _detect_default_branch(repo)
args = [
"pr", "list", "--state", "open", "--limit", str(limit),
"--json", "number,title,headRefName,baseRefName,author,isDraft,"
"reviewDecision,statusCheckRollup,updatedAt",
]
if repo:
args += ["--repo", repo]
raw = _gh(*args)
if raw is None:
raise RuntimeError("gh CLI not found or not authenticated. Run: gh auth login")
prs = []
for item in raw:
updated = datetime.fromisoformat(item["updatedAt"].replace("Z", "+00:00"))
prs.append(PRInfo(
number=item["number"],
title=item["title"],
branch=item["headRefName"],
base_branch=item["baseRefName"],
author=item["author"]["login"] if item.get("author") else "?",
is_draft=item.get("isDraft", False),
review_decision=item.get("reviewDecision") or "",
ci_status=_parse_ci(item.get("statusCheckRollup") or []),
updated_at=updated,
expected_base=resolved_base,
))
return prs
View on GitHub (pinned to 7fe58b0b0f)
Solutions
- Check gh presence and auth: `gh auth status`.
- If not installed: install it (brew install gh / apt install gh / winget) then `gh auth login`.
- In CI, export GH_TOKEN/GITHUB_TOKEN - gh authenticates from the env without interactive login.
- Confirm repo access: `gh pr list --repo <owner>/<repo> --limit 1`.
Example fix
# before $ graphify ingest-prs # RuntimeError: gh CLI not found or not authenticated # after $ gh auth status # see what gh thinks $ gh auth login # interactive; or in CI: $ export GH_TOKEN=ghp_xxx && graphify ingest-prs
Defensive patterns
Strategy: validation
Validate before calling
import shutil, subprocess
def gh_ready() -> bool:
if shutil.which("gh") is None:
return False
r = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True)
return r.returncode == 0
if not gh_ready():
raise SystemExit("gh missing/not authenticated - run: gh auth login") Try / catch
try:
prs = fetch_prs(repo, limit=50)
except RuntimeError as exc:
if "gh CLI" in str(exc):
raise SystemExit("Install/authenticate gh (gh auth login or GH_TOKEN)") from exc
raise Prevention
- Set GH_TOKEN explicitly in CI rather than relying on interactive logins.
- Add `gh auth status` to job preflight for anything touching GitHub.
- Scope tokens to the repos being ingested to avoid revoked-token surprises.
When it happens
Trigger: fetch_prs() is called (PR ingestion for context/extraction) while gh is absent on PATH or its stored token is missing/expired, so _gh(*args) yields None (prs.py:210-211). Includes repo/base-branch resolution via _detect_default_branch first, which also shells out.
Common situations: Fresh machines without gh installed; CI runners where gh exists but GITHUB_TOKEN was never provided; tokens expired or revoked via GitHub settings; gh installed as a snap not on the service PATH.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- No git repository found at or above {path.resolve()}
- Claude Code CLI not found on $PATH
- graph not found: {source_path}
- repo '{repo_tag}' not in global graph
- gws export failed for {file_id}: {stderr}
AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14).
Data as JSON: /api/errors/4797e97b0a7c2a88.
Report an issue: GitHub.