666ghj/MiroFish · error · FetchError

GitHub API redirect was refused

Error message

GitHub API redirect was refused

What it means

Security refusal, not a normal error path. The production opener installs NoRedirectHandler (redirect_request returns None), so a 3xx would surface as HTTPError instead; this geturl() != API_URL check (line 101) fires when a caller passes their own opener via fetch_star_count(token, opener=...) that followed a redirect — the final URL no longer matches https://api.github.com/repos/666ghj/MiroFish. The design goal (per the NoRedirectHandler docstring) is that the Bearer credential must never be forwarded to a different host.

Source

Thrown at scripts/fetch_star_count.py:101

        },
        method="GET",
    )
    client = opener or _build_opener()
    try:
        response = client.open(request, timeout=TIMEOUT_SECONDS)
    except urllib.error.HTTPError as exc:
        status = exc.code
        exc.close()
        raise _status_error(status) from None
    except (urllib.error.URLError, TimeoutError, OSError):
        raise FetchError("GitHub API network request failed") from None
    except Exception:
        raise FetchError("GitHub API request could not be started") from None

    try:
        with response:
            if response.geturl() != API_URL:
                raise FetchError("GitHub API redirect was refused")
            status = response.getcode()
            if status != 200:
                raise _status_error(status)
            payload = _read_response(response)
    except FetchError:
        raise
    except (TimeoutError, OSError):
        raise FetchError("GitHub API response could not be read") from None
    except Exception:
        raise FetchError("GitHub API response could not be processed") from None

    try:
        document = json.loads(payload)
    except (UnicodeDecodeError, json.JSONDecodeError, ValueError):
        raise FetchError("GitHub API returned malformed JSON") from None
    if not isinstance(document, dict):
        raise FetchError("GitHub API response had an unexpected shape")

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Update REPOSITORY/API_URL in scripts/fetch_star_count.py to the repository's new canonical full_name after a rename or transfer (check curl -sI https://api.github.com/repos/666ghj/MiroFish for the Location header).
  2. If you pass a custom opener, build it with the same NoRedirectHandler so 3xx responses fail fast with a status error instead of silently following and then tripping this check.
  3. Never 'fix' this by allowing the redirect — it exists to keep the Authorization header off any other host.

Example fix

# before: caller-supplied opener follows redirects
opener = urllib.request.build_opener()  # default follows 3xx
count = fetch_star_count(token, opener=opener)  # -> redirect was refused

# after: reuse the script's no-redirect policy
from scripts.fetch_star_count import _build_opener
count = fetch_star_count(token, opener=_build_opener())
Defensive patterns

Strategy: try-catch

Validate before calling

import urllib.request
from scripts.fetch_star_count import API_URL

# resolve redirects WITHOUT credentials first; the credentialed call then never 3xx's
req = urllib.request.Request(API_URL, method="HEAD")  # no Authorization header
with urllib.request.urlopen(req, timeout=10) as probe:
    canonical = probe.geturl()
if canonical != API_URL:
    raise SystemExit(f"repo moved; update API_URL to {canonical}")

Try / catch

try:
    count = fetch_star_count(token)
except FetchError as exc:
    if exc.args[0] == "GitHub API redirect was refused":
        # repository likely renamed: look up the new full_name unauthenticated
        raise SystemExit(
            "api.github.com redirected; check if 666ghj/MiroFish was renamed "
            "and update REPOSITORY in scripts/fetch_star_count.py"
        )
    raise

Prevention

When it happens

Trigger: Calling fetch_star_count with a default urllib opener that follows redirects while GitHub answers 301/302/307 — typically because the repository was renamed/transferred, or api.github.com redirects to another canonical host.

Common situations: Repository 666ghj/MiroFish renamed or transferred so /repos/666ghj/MiroFish 301s to the new name; custom test openers that transparently follow redirects; GitHub sunsetting an API host.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/6666fc492245efc1. Report an issue: GitHub.