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

  1. Treat it like any net.OpError dial failure: check with errors.As(*net.OpError) and inspect Op/Err before deciding it is policy-related.
  2. Review the target URL/IP against the configured SSRF allowlist/denylist and use an approved destination.
  3. Capture redirects client-side (CheckRedirect) and stop following chains that leave the permitted address space.
  4. 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

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


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/6354850d1507ea8a. Report an issue: GitHub.