PrefectHQ/fastmcp · error · SSRFFetchError

Timeout fetching {url}

Error message

Timeout fetching {url}

What it means

After every fetch target (one per pinned resolved IP) fails with an httpx TimeoutException, ssrf_safe_fetch_response raises SSRFFetchError('Timeout fetching {url}') chained from the last timeout. Unlike the 'Overall timeout exceeded' variant, each individual request hit its own connect/read/write/pool timeout, and the aggregate budget was not the limiting factor (or was not yet exceeded).

Source

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

                        )
                    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. Verify the target host is up and reachable (curl/ping the resolved IPs directly).
  2. Check firewall/security-group rules — DROP (vs REJECT) produces connect timeouts.
  3. Fix DNS records if they point to stale/decommissioned IPs.
  4. Increase timeout and overall_timeout if the host is merely slow.
  5. Catch SSRFFetchError with the timeout message and retry with exponential backoff.

Example fix

// before
content = await ssrf_safe_fetch(url)  # every resolved IP times out at 10s
// after
try:
    content = await ssrf_safe_fetch(url, timeout=20.0, overall_timeout=90.0)
except SSRFFetchError as e:
    logger.warning("OAuth metadata fetch failed: %s", e)
    content = None
Defensive patterns

Strategy: retry

Validate before calling

import socket
try:
    infos = socket.getaddrinfo(host, 443)
except socket.gaierror:
    raise RuntimeError(f"cannot resolve {host}")
# optionally probe one IP out-of-band before the guarded fetch

Try / catch

try:
    content = await ssrf_safe_fetch(url)
except SSRFFetchError as e:
    if "Timeout fetching" in str(e):
        await asyncio.sleep(5)
        content = await ssrf_safe_fetch(url)  # one bounded retry
    else:
        raise

Prevention

When it happens

Trigger: All resolved IPs of the hostname fail to connect or respond within the per-request timeout (default 10s each); e.g. host is down, firewalled with DROP, or DNS resolves to stale IPs.

Common situations: Target server offline or overloaded; security group / firewall silently dropping packets (no RST, so full timeout); IPv6 connectivity broken so the v6 target always times out; DNS pointing at decommissioned hosts.

Understand the failure class

Related errors


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