666ghj/MiroFish · error · FetchError

GITHUB_TOKEN is missing or invalid

Error message

GITHUB_TOKEN is missing or invalid

What it means

Input validation at the top of fetch_star_count: the token must be non-empty, at most 4096 characters, and contain no CR or LF. The newline checks exist because the token is interpolated into an Authorization header — an embedded \r/\n would allow header injection (request splitting). This is a guard against a malformed GITHUB_TOKEN, not a GitHub-side failure.

Source

Thrown at scripts/fetch_star_count.py:74

def _read_response(response: Any) -> bytes:
    raw_length = response.headers.get("Content-Length")
    if raw_length is not None:
        try:
            content_length = int(raw_length, 10)
        except (TypeError, ValueError) as exc:
            raise FetchError("GitHub API returned invalid response metadata") from exc
        if content_length < 0 or content_length > MAX_HTTP_BYTES:
            raise FetchError("GitHub API response exceeded the size limit")

    payload = response.read(MAX_HTTP_BYTES + 1)
    if len(payload) > MAX_HTTP_BYTES:
        raise FetchError("GitHub API response exceeded the size limit")
    return payload


def fetch_star_count(token: str, opener: Any | None = None) -> int:
    if not token or len(token) > 4_096 or "\r" in token or "\n" in token:
        raise FetchError("GITHUB_TOKEN is missing or invalid")

    request = urllib.request.Request(
        API_URL,
        headers={
            "Accept": "application/vnd.github+json",
            "Authorization": f"Bearer {token}",
            "User-Agent": "Repository-Star-History-Fetcher",
            "X-GitHub-Api-Version": API_VERSION,
        },
        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

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Check the secret wiring: in GitHub Actions confirm the step has env: GITHUB_TOKEN: ${{ secrets.X }} (or uses the auto GITHUB_TOKEN correctly); locally confirm it is exported in the shell running the script.
  2. Strip the value before use: export GITHUB_TOKEN="$(printf '%s' "$GITHUB_TOKEN" | tr -d '\r\n')" — the script intentionally does not strip, so fix the source of the newline.
  3. Verify length/format: a classic ghp_ PAT is ~40 chars; if yours is >4096 or multiline, the wrong value (e.g. a file path or JSON) was assigned.

Example fix

# before (CI step)
- run: python scripts/fetch_star_count.py
  env:
    GITHUB_TOKEN: ${{ secrets.STAR_HISTORY_TOKEN }}
# secret stored with trailing newline -> error

# after: sanitize once at the call site (or fix the secret)
- run: python scripts/fetch_star_count.py
  env:
    GITHUB_TOKEN: ${{ secrets.STAR_HISTORY_TOKEN }}
# and in the wrapper: GITHUB_TOKEN="${GITHUB_TOKEN//$'\n'/}" python scripts/fetch_star_count.py
Defensive patterns

Strategy: validation

Validate before calling

import os

TOKEN_MAX = 4_096

token = os.environ.get("GITHUB_TOKEN", "")
if not token or len(token) > TOKEN_MAX or "\r" in token or "\n" in token:
    raise SystemExit(
        "GITHUB_TOKEN must be set, <=4096 chars, without newlines "
        "(check the CI secret for a trailing newline)"
    )
count = fetch_star_count(token)

Type guard

def is_valid_github_token(value: object) -> bool:
    """True when value can be safely placed in an Authorization header."""
    return (
        isinstance(value, str)
        and 0 < len(value) <= 4_096
        and "\r" not in value
        and "\n" not in value
    )

Try / catch

try:
    count = fetch_star_count(os.environ.get("GITHUB_TOKEN", ""))
except FetchError as exc:
    if exc.args[0] == "GITHUB_TOKEN is missing or invalid":
        raise SystemExit("CI: add GITHUB_TOKEN to the step env / strip trailing newline")
    raise

Prevention

When it happens

Trigger: GITHUB_TOKEN unset or empty (os.environ.get('GITHUB_TOKEN', '') yields ''); a token with trailing newline/whitespace pasted from a CI secret (the classic trailing \n in GitHub Actions/GitLab CI secrets); a token longer than 4096 chars; a multiline value accidentally assigned.

Common situations: CI scheduled workflow missing the GITHUB_TOKEN secret in env:; secret copied with quotes/newline into .env; runner injecting the variable with surrounding whitespace; passing the wrong env var name.

Related errors


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