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

  1. Ensure upstream URLs include an explicit host and port.
  2. Wrap IPv6 literals in brackets, e.g. http://[::1]:8080.
  3. 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

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


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/372102673d6fea83.json. Report an issue: GitHub.