unslothai/unsloth · critical · GitHubAuthError

GitHub {endpoint} returned {r.status_code} {r.reason}. Token

Error message

GitHub {endpoint} returned {r.status_code} {r.reason}. Token source: {self._token_source}. The token is invalid, expired, or missing required scopes — retrying will not recover.{request_id_message} Response: {snippet}

What it means

GitHubAuthError raised by _raise_auth_error for GitHub responses where the client determined the failure is non-retryable: HTTP 401 always, and 403 only when it is NOT a rate-limit response (checked via Retry-After / X-RateLimit-Remaining: 0 / abuse detection text). The message includes the endpoint, status, token source, GitHub request ID, and first 200 bytes of the response body so the user can diagnose scope/expiry issues. Retrying will not help — the token itself is bad.

Source

Thrown at studio/backend/plugins/data-designer-github-repo-seed/src/data_designer_github_repo_seed/scraper_impl/gh_client.py:128

        )

    def _is_auth_failure(self, r: "requests.Response") -> bool:
        """Tell auth failures apart from rate limiting on 401/403.

        401 is always auth; 403 is auth unless it carries a rate-limit signal
        (Retry-After, X-RateLimit-Remaining: 0, or abuse/secondary text).
        """
        if r.status_code == 401:
            return True
        if r.status_code == 403:
            return not self._is_rate_limit_response(r)
        return False

    def _raise_auth_error(self, r: "requests.Response", endpoint: str) -> None:
        snippet = (r.text or "").strip()[:200]
        request_id = r.headers.get("X-GitHub-Request-Id")
        request_id_message = f" Request ID: {request_id}." if request_id else ""
        raise GitHubAuthError(
            f"GitHub {endpoint} returned {r.status_code} {r.reason}. "
            f"Token source: {self._token_source}. "
            f"The token is invalid, expired, or missing required scopes — "
            f"retrying will not recover.{request_id_message} Response: {snippet}"
        )

    def _check_rate_and_wait(self, kind: str) -> None:
        if kind == "graphql":
            remaining = self.graphql_remaining
            reset = self.graphql_reset
            min_remaining = self.min_remaining_graphql
        else:
            remaining = self.rest_remaining
            reset = self.rest_reset
            min_remaining = self.min_remaining_rest
        if remaining is not None and remaining < min_remaining:
            if reset:
                self._sleep_until(reset)

View on GitHub (pinned to 203007d190)

Solutions

  1. Regenerate or extend the token and update GH_TOKEN/GITHUB_TOKEN (or the recipe token field).
  2. For fine-grained PATs, grant access to the specific repos/orgs and required permissions (contents, issues, pull requests read).
  3. For org repos, authorize the token for SSO/SAML in GitHub settings if the org enforces it.
  4. Use the Request ID in the message when contacting GitHub support.

Example fix

# before
export GH_TOKEN="ghp_expiredtoken..."

# after
# create a fresh token with repo scope at https://github.com/settings/tokens
export GH_TOKEN="ghp_newtoken..."
Defensive patterns

Strategy: try-catch

Try / catch

from data_designer_github_repo_seed.scraper_impl.gh_client import GitHubAuthError

try:
    client.fetch_repo_issues("owner/name")
except GitHubAuthError as e:
    msg = str(e)
    if "401" in msg or "403" in msg:
        # non-retryable: rotate/fix the token, check scopes/SSO, then re-run
        report_fatal_auth(msg)  # includes token source + GitHub Request ID
    raise

Prevention

When it happens

Trigger: Any GraphQL or REST call returning 401 (bad/expired/revoked token), or 403 for reasons other than rate limiting (SSO authorization missing, fine-grained PAT without access to the org/repo, missing scope like repo for a private repo).

Common situations: Token expired or revoked between runs; fine-grained PAT not granted to the target organization or lacking the 'contents:read' scope; organization requires SSO/SAML authorization the PAT never received; classic PAT without repo scope hitting private repos.

Understand the failure class

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/42bc43cf702d64ad. Report an issue: GitHub.