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
- 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).
- 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.
- 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
- After renaming/transferring the repo, immediately update REPOSITORY in both scripts (fetch_star_count.py and star_history.py share it).
- Always use the script's _build_opener() (no-redirect) when supplying a custom opener — never a default opener that forwards the Bearer token.
- Monitor for 301s with a credential-free HEAD check in CI so a rename fails loudly outside the credentialed path.
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
- GITHUB_TOKEN is missing or invalid
- GitHub API returned invalid response metadata
- GitHub API response exceeded the size limit
- GitHub API network request failed
- GitHub API request could not be started
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/6666fc492245efc1.
Report an issue: GitHub.