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

  1. Check gh presence and auth: `gh auth status`.
  2. If not installed: install it (brew install gh / apt install gh / winget) then `gh auth login`.
  3. In CI, export GH_TOKEN/GITHUB_TOKEN - gh authenticates from the env without interactive login.
  4. 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

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

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/4797e97b0a7c2a88. Report an issue: GitHub.