gofiber/fiber · error
proxy: invalid dial address %q: %w
Error message
proxy: invalid dial address %q: %w
What it means
Returned by the SSRF dialer (newSSRFDialer) when net.SplitHostPort cannot parse the address being dialed. This is an internal dial-path invariant failure on a malformed host:port string.
Source
Thrown at middleware/proxy/security.go:433
}
return nil
}
// newSSRFDialer returns a fasthttp DialFunc that resolves the target host
// (with a bounded timeout), rejects the connection if any resolved
// address falls in a blocked range, and then dials a validated address.
// Performing the check at dial time — rather than only up front — defeats
// DNS-rebinding attacks (the check/use gap) where a resolver returns a
// public address during validation and a private one at connect time. It
// is only installed when the active policy disallows private IPs.
//
//nolint:revive // dialDualStack mirrors fasthttp.HostClient.DialDualStack
func newSSRFDialer(dialDualStack bool) fasthttp.DialFunc {
dialer := &net.Dialer{Timeout: dnsLookupTimeout}
return func(addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("proxy: invalid dial address %q: %w", addr, err)
}
ips, err := resolveAndValidateHost(host)
if err != nil {
return nil, err
}
return dialValidatedIPs(ips, host, port, dialDualStack, dialer.Dial)
}
}
// resolveAndValidateHost looks up host (or treats it as an IP literal),
// then enforces the SSRF blocklist on every returned address. A single
// blocked answer fails the whole resolution so a mixed public/private
// reply cannot slip past the guard.
func resolveAndValidateHost(host string) ([]net.IP, error) {
var ips []net.IP
if ip := net.ParseIP(host); ip != nil {
ips = []net.IP{ip}
} else {View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Ensure upstream URLs include an explicit host and port.
- Wrap IPv6 literals in brackets, e.g. http://[::1]:8080.
- Sanitize upstream config before it reaches the proxy.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure upstream URLs carry a host and port before proxying.
func hasHostPort(raw string) error {
u, err := url.Parse(raw)
if err != nil { return err }
if u.Port() == "" || u.Hostname() == "" {
return fmt.Errorf("upstream must include host and port")
}
return nil
} Try / catch
if strings.Contains(err.Error(), "invalid dial address") {
return fiber.NewError(fiber.StatusBadGateway, "malformed upstream address")
} Prevention
- Always include an explicit port in upstream URLs.
- Bracket IPv6 literals: http://[::1]:8080.
- Sanitize upstream config before it reaches the proxy.
When it happens
Trigger: The fasthttp dialer invokes the SSRF guard with an addr that net.SplitHostPort rejects (security.go:431-433), e.g. missing port, unbalanced brackets, or empty address. Normally fasthttp always supplies a valid host:port.
Common situations: A custom/malformed upstream address reaching the dialer; an IPv6 literal without brackets; a bug in upstream URL construction stripping the port.
Related errors
- proxy: upstream scheme is not allowed
- proxy: upstream host is empty or invalid
- proxy: upstream host resolves to a blocked address
- ErrUpstreamSchemeNotAllowed
- ErrUpstreamHostBlocked
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/372102673d6fea83.json.
Report an issue: GitHub.