nats-io/nats-server · error
%w: invalid address
Error message
%w: invalid address
What it means
The v1 header's source or destination IP field failed net.ParseIP, meaning it is neither a valid IPv4 dotted-quad nor a valid IPv6 literal. The server rejects the header with an error wrapping errProxyProtoInvalid because the addresses cannot represent a real connection.
Source
Thrown at server/client_proxyproto.go:194
return nil, nil, fmt.Errorf("%w: invalid v1 format", errProxyProtoInvalid)
}
// Handle UNKNOWN (health check, like v2 LOCAL)
if parts[0] == proxyProtoV1Unknown {
return nil, remaining, nil
}
// Must have exactly 5 parts: protocol, src-ip, dst-ip, src-port, dst-port
if len(parts) != 5 {
return nil, nil, fmt.Errorf("%w: invalid v1 format", errProxyProtoInvalid)
}
protocol := parts[0]
srcIP := net.ParseIP(parts[1])
dstIP := net.ParseIP(parts[2])
if srcIP == nil || dstIP == nil {
return nil, nil, fmt.Errorf("%w: invalid address", errProxyProtoInvalid)
}
// Parse ports
srcPort, err := strconv.ParseUint(parts[3], 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("invalid source port: %w", err)
}
dstPort, err := strconv.ParseUint(parts[4], 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("invalid dest port: %w", err)
}
// Validate protocol matches IP version. The textual form determines the
// family: TCP4 requires dotted-quad addresses, TCP6 requires IPv6
// addresses. IPv4-mapped IPv6 addresses (e.g. "::ffff:192.0.2.1") are
// valid for TCP6 since dual-stack proxies can emit those for IPv4
// clients on IPv6 sockets, matching the v2 parser behavior.View on GitHub (pinned to 3a66a489d2)
Solutions
- Confirm the sender writes valid IPv4 dotted-quad or IPv6 literals in both address fields
- Fix proxy config that substitutes hostnames (e.g. 'localhost') instead of IPs
- Log/inspect the raw header (tcpdump) to see exactly which field is bad
- Update broken test fixtures to use valid addresses like 192.0.2.1 (TEST-NET)
Example fix
// before "PROXY TCP4 localhost 198.51.100.7 35646 4222\r\n" // after "PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\r\n"
Defensive patterns
Strategy: validation
Validate before calling
src := net.ParseIP(srcIPStr)
dst := net.ParseIP(dstIPStr)
if src == nil || dst == nil {
return fmt.Errorf("cannot send PROXY header: invalid IP %q / %q", srcIPStr, dstIPStr)
} Type guard
func parseableIPs(parts []string) bool {
return net.ParseIP(parts[1]) != nil && net.ParseIP(parts[2]) != nil
} Try / catch
addr, _, err := readProxyProtoHeader(conn)
if err != nil {
if errors.Is(err, errProxyProtoInvalid) && strings.Contains(err.Error(), "invalid address") {
log.Printf("PROXY header had unparseable IP: %v", err)
return
}
return err
} Prevention
- Always send IPs, never hostnames, in v1 headers
- Resolve hostnames to IPs in the proxy before header emission
- Use net.ParseIP as a pre-flight check in custom senders
- Prefer v2 binary headers, which carry raw IP bytes and cannot be malformed text
When it happens
Trigger: Header contains malformed IP text such as 'PROXY TCP4 999.1.1.1 198.51.100.7 35646 4222\r\n', hostnames instead of IPs, or empty address fields.
Common situations: Proxy template using hostname instead of resolved IP; misconfigured transparent proxy passing through garbage; double proxying where an inner header leaks; typo in a hand-written test fixture.
Related errors
- %w: v1 line too long
- %w: invalid v1 format
- invalid source port: %w
- invalid dest port: %w
- %w: TCP4 with IPv6 address
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/93097637502e7ecf.
Report an issue: GitHub.