unslothai/unsloth · error · RuntimeError

GraphQL failed after {max_retries} retries: {last_err}

Error message

GraphQL failed after {max_retries} retries: {last_err}

What it means

RuntimeError raised after the GraphQL request exhausts max_retries attempts. Each attempt that fails with a requests.RequestException (connection error, timeout, DNS failure) is logged, followed by exponential backoff (doubling, capped at 60s); after the final attempt the last exception is re-raised wrapped in this message. Note: GraphQL-level errors inside a 200 response are treated differently — rate-limit errors trigger retry, others are logged and partial data returned, so this error specifically means transport-level failures.

Source

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

                if "errors" in data and data["errors"]:
                    # Allow partial data; retry on RATE_LIMITED
                    errs = data["errors"]
                    for e in errs:
                        if e.get("type") == "RATE_LIMITED":
                            self._sleep_until((self.graphql_reset or int(time.time()) + 60))
                            break
                    else:
                        # No rate-limit error: log and return partial
                        log.warning("GraphQL errors: %s", json.dumps(errs)[:400])
                        return data
                    continue
                return data
            except requests.RequestException as e:
                last_err = e
                log.warning("GraphQL network error: %s. Retry.", e)
                time.sleep(backoff)
                backoff = min(backoff * 2, 60)
        raise RuntimeError(f"GraphQL failed after {max_retries} retries: {last_err}")

    def rest(
        self,
        method: str,
        path: str,
        params: Optional[Dict[str, Any]] = None,
        json_body: Optional[Dict[str, Any]] = None,
        max_retries: int = 6,
    ) -> requests.Response:
        self._check_rate_and_wait("rest")
        if path.startswith("http"):
            url = path
        else:
            url = REST_BASE + path
        backoff = 2
        last_err = None
        for attempt in range(max_retries):
            try:

View on GitHub (pinned to 203007d190)

Solutions

  1. Check basic connectivity: curl -sS https://api.github.com from the same host/container.
  2. Fix proxy/DNS configuration (HTTP_PROXY/HTTPS_PROXY, resolv.conf) so api.github.com is reachable.
  3. Re-run the job once the network is stable; the scraper is resumable across runs via its cache.
  4. If the environment is flaky by design, raise max_retries when calling graphql().

Example fix

# before
$ python scrape.py  # RuntimeError: GraphQL failed after 6 retries: ...ProxyError...

# after
$ unset HTTP_PROXY HTTPS_PROXY  # or fix proxy to allow api.github.com
$ python scrape.py
Defensive patterns

Strategy: retry

Validate before calling

import socket

def github_api_reachable(timeout: float = 5.0) -> bool:
    try:
        socket.create_connection(("api.github.com", 443), timeout=timeout).close()
        return True
    except OSError:
        return False

Try / catch

try:
    data = client.graphql(query)
except RuntimeError as e:
    if "GraphQL failed after" in str(e):
        # transient transport failure: back off and restart the job (cache resumes)
        time.sleep(300)
        restart_job()
    else:
        raise

Prevention

When it happens

Trigger: Network outage, proxy/DNS failure, firewall blocking api.github.com, or TLS interception failing — repeatedly — for the whole retry window (6 attempts with exponential backoff).

Common situations: Corporate proxies blocking api.github.com; transient ISP/DNS problems during long scrape runs; container with broken resolv.conf; GitHub itself briefly unreachable from the runner's network.

Related errors


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