caddyserver/caddy · error

local_address must be a TCP address, not a UDP address

Error message

local_address must be a TCP address, not a UDP address

What it means

local_address must identify a TCP-family (or unix socket) address because it is fed to net.Dialer.LocalAddr via net.ResolveTCPAddr/ResolveUnixAddr. Explicitly UDP networks (udp, udp4, udp6) are rejected with this message during transport setup.

Source

Thrown at modules/caddyhttp/reverseproxy/httptransport.go:253

		if err != nil {
			return nil, err
		}
		if netaddr.PortRangeSize() > 1 {
			return nil, fmt.Errorf("local_address must be a single address, not a port range")
		}
		switch netaddr.Network {
		case "tcp", "tcp4", "tcp6":
			dialer.LocalAddr, err = net.ResolveTCPAddr(netaddr.Network, netaddr.JoinHostPort(0))
			if err != nil {
				return nil, err
			}
		case "unix", "unixgram", "unixpacket":
			dialer.LocalAddr, err = net.ResolveUnixAddr(netaddr.Network, netaddr.JoinHostPort(0))
			if err != nil {
				return nil, err
			}
		case "udp", "udp4", "udp6":
			return nil, fmt.Errorf("local_address must be a TCP address, not a UDP address")
		default:
			return nil, fmt.Errorf("unsupported network")
		}
	}
	if h.Resolver != nil {
		err := h.Resolver.ParseAddresses()
		if err != nil {
			return nil, err
		}
		d := &net.Dialer{
			Timeout:       time.Duration(h.DialTimeout),
			FallbackDelay: time.Duration(h.FallbackDelay),
		}
		dialer.Resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
				//nolint:gosec
				addr := h.Resolver.netAddrs[weakrand.IntN(len(h.Resolver.netAddrs))]

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Remove the udp network prefix: use local_address 10.0.0.5 or tcp/10.0.0.5
  2. Note that HTTP/3 upstream connections are handled by the h3 transport, not by this dialer's local_address

Example fix

# before
transport http {
	local_address udp/10.0.0.5
}
# after
transport http {
	local_address 10.0.0.5
}
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasPrefix(localAddr, "udp") {
	return fmt.Errorf("local_address: UDP not supported; use tcp")
}

Prevention

When it happens

Trigger: `transport http { local_address udp://10.0.0.5:0 }` or `local_address udp6/::1` in JSON config.

Common situations: Confusing the upstream dial address format with the local bind address; infrastructure docs that describe the interface as UDP (e.g. QUIC/HTTP3 front-end) leading the operator to try a UDP local_address for the outbound proxy connection.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/79817568cc5908c5. Report an issue: GitHub.