{"record":{"id":"06af572e6bebbf1c","repo":"gofiber/fiber","slug":"w-s-has-no-usable-address","errorCode":null,"errorMessage":"%w: %s has no usable address","messagePattern":"%w: (.+?) has no usable address","errorType":"validation","errorClass":"ErrUpstreamHostBlocked","httpStatus":null,"severity":"error","filePath":"middleware/proxy/security.go","lineNumber":492,"sourceCode":"// \"no usable address\" error is returned; otherwise the last dial error\n// is propagated so the caller can see why each attempt failed.\n//\n//nolint:revive // dialDualStack mirrors fasthttp.HostClient.DialDualStack\nfunc dialValidatedIPs(ips []net.IP, host, port string, dialDualStack bool, dial ssrfDialFunc) (net.Conn, error) {\n\tvar lastErr error\n\tfor _, ip := range ips {\n\t\t// Mirror fasthttp's default of IPv4-only unless DialDualStack.\n\t\tif !dialDualStack && ip.To4() == nil {\n\t\t\tcontinue\n\t\t}\n\t\tconn, derr := dial(\"tcp\", net.JoinHostPort(ip.String(), port))\n\t\tif derr == nil {\n\t\t\treturn conn, nil\n\t\t}\n\t\tlastErr = derr\n\t}\n\tif lastErr == nil {\n\t\tlastErr = fmt.Errorf(\"%w: %s has no usable address\", ErrUpstreamHostBlocked, host)\n\t}\n\treturn nil, lastErr\n}\n\n// installHostClientGuard fits hc with the policy-aware, dial-time SSRF\n// guard. It is installed through fasthttp.Client.ConfigureClient, which\n// runs once per HostClient at creation — so the guard is present before the\n// first dial to that host and, crucially, covers BOTH dial code paths:\n// fasthttp's callDialFunc prefers DialTimeout over Dial, so guarding only\n// Dial would let a client that sets DialTimeout dial unvalidated. We wrap\n// DialTimeout when present (preserving its per-request timeout) and always\n// wrap Dial so the nil-DialTimeout and default-dialer paths are guarded too.\nfunc installHostClientGuard(hc *fasthttp.HostClient) {\n\tif hc.DialTimeout != nil {\n\t\thc.DialTimeout = newGuardedClientDialerWithTimeout(hc.DialTimeout, hc.DialDualStack)\n\t}\n\thc.Dial = newGuardedClientDialer(hc.Dial, hc.DialDualStack)\n}","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/proxy/security.go#L474-L510","documentation":"dialValidatedIPs walks the resolved IP list and skips IPv6 addresses when dialDualStack is false (mirroring fasthttp's IPv4-only default). If every candidate is skipped (IPv6-only host with dialDualStack=false) or the list was empty, this error is returned instead of a dial error. If dials were attempted but all failed, the last dial error is returned instead — so this specific message means no dial was even attempted.","triggerScenarios":"Hostname resolves to IPv6-only (AAAA-only, no A records) and the HostClient has DialDualStack=false (the fasthttp default); an empty resolved list slipped past earlier guards; all resolved IPs were skipped as IPv6.","commonSituations":"IPv6-only upstream service reached from an IPv4-default HostClient; a hostname that recently lost its A record; a service on an IPv6-only network (some mobile/telco backends); HostClient created without DialDualStack=true.","solutions":["Confirm the host has IPv4 (A) records if you cannot enable dual-stack: dig A hostname +short.","If the upstream is legitimately IPv6-capable and your network supports it, enable DialDualStack on the HostClient / fasthttp.Client.","If IPv4 is required, ask the upstream operator to publish A records.","Verify your runtime network has IPv4 connectivity before relying on it.","Log the resolved IPs at debug level to see what dialValidatedIPs received."],"exampleFix":"// before: IPv6-only upstream, IPv4-default client\nbalancer.HostClient.DialDualStack = false // 197 fires\n\n// after: enable dual stack\nbalancer.HostClient.DialDualStack = true","handlingStrategy":"validation","validationCode":"func hasIPv4(host string) bool {\n  ips, _ := net.LookupIP(host)\n  for _, ip := range ips { if ip.To4() != nil { return true } }\n  return false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Confirm upstreams publish A records if DialDualStack is false.","Enable DialDualStack when upstreams and your network are IPv6-capable.","Log resolved IPs at debug level to see what dialValidatedIPs received.","Audit HostClient.DialDualStack settings in config."],"tags":["proxy","ipv6","dialer","dual-stack","network"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}