PrefectHQ/fastmcp · error · SSRFFetchError
Error fetching {url}: no fetch targets succeeded
Error message
Error fetching {url}: no fetch targets succeeded What it means
Raised when _build_fetch_targets produced zero targets or every target failed while last_error was somehow unset — the terminal fallback in ssrf_safe_fetch_response (ssrf.py:540). In practice it signals that no SSRF-validated fetch target could even be attempted, i.e. the validated URL resolved to no connectable addresses.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/ssrf.py:540
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
- Log and report the URL and DNS state; this indicates an edge case, so capture e.__cause__ context if present.
- Re-run validate_url() on the URL to inspect what targets would be built.
- Check DNS resolution of the hostname (dig/host) for empty or unusual answers.
- Catch SSRFFetchError and treat the host as unreachable; retry later or alert.
- If reproducible, file a bug with the URL's DNS records — all normal failures should surface as errors 386/387 instead.
Example fix
// before
resp = await ssrf_safe_fetch_response(url) # opaque 'no fetch targets succeeded'
// after
try:
resp = await ssrf_safe_fetch_response(url)
except SSRFFetchError as e:
if "no fetch targets succeeded" in str(e):
logger.error("No SSRF targets for %s; check DNS", url)
raise Defensive patterns
Strategy: try-catch
Validate before calling
import socket
infos = socket.getaddrinfo(host, None)
addrs = {i[4][0] for i in infos}
if not addrs:
raise RuntimeError(f"{host} resolves to no addresses") Try / catch
try:
resp = await ssrf_safe_fetch_response(url)
except SSRFFetchError as e:
if "no fetch targets succeeded" in str(e):
logger.error("No SSRF targets for %s; DNS: check records", url)
raise Prevention
- Verify DNS records are sane (A/AAAA present, not CNAME-only edge cases)
- Log resolved IPs alongside this error to diagnose target construction
- Reproduce with validate_url() and report persistent cases as a bug
When it happens
Trigger: validate_url resolved the hostname but the pinned-IP target list is empty (e.g. empty DNS answer after validation edge cases); all targets raised and error capture missed; internal invariant violation in target construction.
Common situations: Hostname with only unusual record types after validation filtering; edge cases in proxy mode where a single unpinned target fails before recording an error; rare logic path after per-target RequestError handling.
Related errors
- Timeout fetching {url}
- {str(e) from SSRFError/SSRFFetchError}
- Failed to fetch JWKS: {e}
- Overall timeout exceeded: {url}
- HTTP {response.status_code} fetching {url}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/130b5c2a590b8914.
Report an issue: GitHub.