PrefectHQ/fastmcp · error · SSRFFetchError

Error fetching {url}: {last_error}

Error message

Error fetching {url}: {last_error}

What it means

When all fetch targets fail with a non-timeout httpx RequestError (connection refused, TLS failure, DNS error at connect time, etc.), ssrf_safe_fetch_response raises SSRFFetchError('Error fetching {url}: {last_error}') chained from the final underlying exception. The message embeds the last error seen across all tried targets.

Source

Thrown at fastmcp_slim/fastmcp/server/auth/ssrf.py:538

                    chunks.append(chunk)

                return SSRFFetchResponse(
                    content=b"".join(chunks),
                    status_code=response.status_code,
                    headers=dict(response.headers),
                )

        except httpx2.TimeoutException as e:
            last_error = e
            continue
        except httpx2.RequestError as e:
            last_error = e
            continue

    if last_error is not None:
        if isinstance(last_error, httpx2.TimeoutException):
            raise SSRFFetchError(f"Timeout fetching {url}") from last_error
        raise SSRFFetchError(f"Error fetching {url}: {last_error}") from last_error

    raise SSRFFetchError(f"Error fetching {url}: no fetch targets succeeded")

View on GitHub (pinned to 1f02114297)

Solutions

  1. Read the chained cause (e.__cause__) or the embedded last_error for the specific network failure.
  2. Check certificate validity of the target host (expired, self-signed, missing chain) — verification cannot be disabled by design.
  3. Confirm the URL's scheme/port is correct and the service is listening.
  4. If behind a proxy environment, test whether trust_env proxy settings interfere with the pinned-IP connection.
  5. Catch SSRFFetchError and apply retry-with-backoff for transient connection errors.

Example fix

// before
content = await ssrf_safe_fetch(issuer_url)  # SSRFFetchError: ... certificate verify failed
// after
try:
    content = await ssrf_safe_fetch(issuer_url)
except SSRFFetchError as e:
    if "certificate" in str(e):
        raise RuntimeError(f"TLS misconfiguration at {issuer_url}") from e
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-check TLS out-of-band
import ssl, socket
ctx = ssl.create_default_context()
with socket.create_connection((host, 443), timeout=5) as s:
    with ctx.wrap_socket(s, server_hostname=host):
        pass  # raises ssl.SSLError on bad certs before the guarded fetch

Try / catch

try:
    content = await ssrf_safe_fetch(url)
except SSRFFetchError as e:
    logger.error("fetch failed: %s (cause: %r)", e, e.__cause__)
    raise

Prevention

When it happens

Trigger: Connection refused (port closed), TLS certificate verification failure (verify=True is always on), SSL handshake errors, network unreachable, or proxy connection errors — on every pinned IP.

Common situations: Fetching HTTPS metadata from a host with a self-signed/expired certificate; wrong port in the URL; server actively refusing connections (service not running); corporate proxy interference in proxy mode; stale DNS to a torn-down host.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/32946929a09ccb69. Report an issue: GitHub.