tiangolo/fastapi · error · RuntimeError

response.text

Error message

response.text

What it means

Raised by get_graphql_response() in scripts/sponsors.py:109 when the GitHub Sponsors GraphQL request returns a non-200 HTTP status. response.text is raised as the message so the API error text is preserved. This is the transport/auth failure path; GraphQL-level errors are handled separately at line 115.

Source

Thrown at scripts/sponsors.py:109

def get_graphql_response(
    *,
    settings: Settings,
    query: str,
    after: str | None = None,
) -> dict[str, Any]:
    headers = {"Authorization": f"token {settings.sponsors_token.get_secret_value()}"}
    variables = {"after": after}
    response = httpx.post(
        github_graphql_url,
        headers=headers,
        timeout=settings.httpx_timeout,
        json={"query": query, "variables": variables, "operationName": "Q"},
    )
    if response.status_code != 200:
        logging.error(f"Response was not 200, after: {after}")
        logging.error(response.text)
        raise RuntimeError(response.text)
    data = response.json()
    if "errors" in data:
        logging.error(f"Errors in response, after: {after}")
        logging.error(data["errors"])
        logging.error(response.text)
        raise RuntimeError(response.text)
    return data


def get_graphql_sponsor_edges(
    *, settings: Settings, after: str | None = None
) -> list[SponsorshipAsMaintainerEdge]:
    data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
    graphql_response = SponsorsResponse.model_validate(data)
    return graphql_response.data.user.sponsorshipsAsMaintainer.edges


def get_individual_sponsors(

View on GitHub (pinned to 3e8d1526d8)

Solutions

  1. Inspect the logged response.text (scripts/sponsors.py:108 logs it at ERROR) for the exact API message.
  2. Rotate SPONSORS_TOKEN and ensure it can read GitHub Sponsors data for the target user.
  3. For rate limits, back off and retry; for 5xx, retry after a delay.
  4. Confirm httpx_timeout (default 30s) is sufficient for the sponsors query.
Defensive patterns

Strategy: retry

Validate before calling

import os

def sponsors_token_present() -> bool:
    return bool(os.environ.get("SPONSORS_TOKEN"))

Try / catch

import time, logging
for attempt in range(4):
    try:
        data = get_graphql_response(settings=settings, query=sponsors_query)
        break
    except RuntimeError as e:
        if attempt == 3:
            raise
        logging.warning(f"Sponsors GraphQL HTTP error, retrying: {e}")
        time.sleep(2 ** attempt)

Prevention

When it happens

Trigger: sponsors.main() issues a GraphQL POST to https://api.github.com/graphql authenticated with sponsors_token (scripts/sponsors.py:98). Any status_code != 200 raises here — 401/403 for token/scope issues (the sponsors_token must have access to the user(login: 'tiangolo') sponsorshipsAsMaintainer field), 429 rate limit, 5xx outage.

Common situations: SPONSORS_TOKEN expired or revoked. Token is a fine-grained PAT without the sponsors:read scope. Rate limited during a scheduled CI run. GitHub incident.

Related errors


AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11). Data as JSON: /api/errors/d1969bac88cbc8df. Report an issue: GitHub.