ory/hydra · error
no route to host
Error message
no route to host
What it means
ipx's SSRF dialing layer fabricates a *net.OpError{Op:"dial"} wrapping errors.New("no route to host") when it must abort a connection attempt (e.g. redirect/blocked-dial simulation in ssrf.go). It mimics the classic EHOSTUNREACH network error so standard net.Error handling applies.
Source
Thrown at oryx/ipx/ssrf.go:97
return nil, &net.OpError{
Op: "dial",
Net: network,
Addr: nil,
Err: &net.DNSError{
Err: "no such host",
Name: host,
Server: "",
IsTimeout: false,
IsTemporary: false,
IsNotFound: true,
},
}
}
return nil, &net.OpError{
Op: "dial",
Net: network,
Addr: nil,
Err: errors.New("no route to host"),
}
}
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Treat it like any net.OpError dial failure: check with errors.As(*net.OpError) and inspect Op/Err before deciding it is policy-related.
- Review the target URL/IP against the configured SSRF allowlist/denylist and use an approved destination.
- Capture redirects client-side (CheckRedirect) and stop following chains that leave the permitted address space.
- Distinguish policy blocks from genuine network issues by logging the resolved IP alongside the error.
Example fix
// before
resp, err := client.Do(req) // err: dial: no route to host
// after
var opErr *net.OpError
if errors.As(err, &opErr) && opErr.Op == "dial" {
log.Printf("blocked/unreachable dial to %s: %v", req.URL.Host, err)
return ErrBlockedBySSRFGuard
} Defensive patterns
Strategy: type-guard
Validate before calling
// before requesting, check the target is allowed:
ip, err := netip.ParseAddr(hostOrIP)
if err != nil { return fmt.Errorf("bad host %q", host) }
if !ssrfAllowlist.Contains(ip) { return ErrDestinationNotAllowed } Type guard
func isNoRouteToHost(err error) bool {
var opErr *net.OpError
return errors.As(err, &opErr) && opErr.Op == "dial" &&
strings.Contains(opErr.Err.Error(), "no route to host")
} Try / catch
resp, err := client.Do(req)
if err != nil {
var opErr *net.OpError
if errors.As(err, &opErr) && isNoRouteToHost(err) {
return ErrBlockedOrUnreachable // treat as policy/routing refusal
}
return err
} Prevention
- Keep the SSRF allowlist/denylist aligned with the destinations your app calls
- Stop redirect following into unapproved address space (custom CheckRedirect)
- Log resolved IPs with dial failures to separate policy blocks from network faults
- Pre-validate URLs against the policy before issuing requests
When it happens
Trigger: Making an HTTP request through the ipx SSRF-guarded dialer when the guard decides the destination is unreachable/not routable under policy — the dial is refused and a synthetic "no route to host" *net.OpError is returned instead of opening a socket.
Common situations: Requests to hosts whose resolved IPs are blocked by the SSRF allow/deny policy; redirects to disallowed targets where the guarded dialer terminates the connection; tests exercising blocked-dial paths.
Related errors
- ip %s is not a permitted destination
- DNS lookup timed out
- key %s validation is failing
- global secret is too short
- file loader disabled
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/6354850d1507ea8a.
Report an issue: GitHub.