nats-io/nats-server · error
IPv6 address data too short: %d bytes
Error message
IPv6 address data too short: %d bytes
What it means
parseIPv6Addr requires at least proxyProtoAddrSizeIPv6 (36) bytes of address data for an AF_INET6 v2 header (16 src IP + 16 dst IP + 2 src port + 2 dst port). The header's declared addrLen was smaller, so the payload cannot hold a valid IPv6 endpoint pair and parsing fails without reading.
Source
Thrown at server/client_proxyproto.go:403
return nil, fmt.Errorf("IPv4 address data too short: %d bytes", addrLen)
}
addrData := make([]byte, addrLen)
if _, err := io.ReadFull(conn, addrData); err != nil {
return nil, fmt.Errorf("failed to read IPv4 address data: %w", err)
}
return &proxyProtoAddr{
srcIP: net.IP(addrData[0:4]),
dstIP: net.IP(addrData[4:8]),
srcPort: binary.BigEndian.Uint16(addrData[8:10]),
dstPort: binary.BigEndian.Uint16(addrData[10:12]),
}, nil
}
// parseIPv6Addr parses IPv6 address data from PROXY protocol header
func parseIPv6Addr(conn net.Conn, addrLen uint16) (*proxyProtoAddr, error) {
// IPv6: 16 (src IP) + 16 (dst IP) + 2 (src port) + 2 (dst port) = 36 bytes minimum
if addrLen < proxyProtoAddrSizeIPv6 {
return nil, fmt.Errorf("IPv6 address data too short: %d bytes", addrLen)
}
addrData := make([]byte, addrLen)
if _, err := io.ReadFull(conn, addrData); err != nil {
return nil, fmt.Errorf("failed to read IPv6 address data: %w", err)
}
return &proxyProtoAddr{
srcIP: net.IP(addrData[0:16]),
dstIP: net.IP(addrData[16:32]),
srcPort: binary.BigEndian.Uint16(addrData[32:34]),
dstPort: binary.BigEndian.Uint16(addrData[34:36]),
}, nil
}
View on GitHub (pinned to 3a66a489d2)
Solutions
- Correct the proxy to declare 36 bytes of address data for AF_INET6 v2 headers.
- Prefer forcing IPv4 upstream (set resolver/address family) so the proxy emits AF_INET headers if it only supports them correctly.
- Update the emitting proxy software if it is a known bug in an older version.
Example fix
// before binary.BigEndian.PutUint16(lenBuf, 12) // IPv4 length used for IPv6 // after binary.BigEndian.PutUint16(lenBuf, 36) // 16+16+2+2
Defensive patterns
Strategy: validation
Validate before calling
if hdr[14] == 0x21 && addrLen < 36 {
return fmt.Errorf("IPv6 v2 header needs >=36 addr bytes, got %d", addrLen)
} Type guard
func validIPv6AddrLen(n uint16) bool { return n >= 36 } Prevention
- Compute the v2 address length from the family: 12 for IPv4, 36 for IPv6
- Pin the proxy to IPv4 upstreams if it mishandles IPv6 lengths
- Unit-test header building for both address families
When it happens
Trigger: A v2 PROXY header with family byte 0x21 but address-length less than 36, e.g. a sender copying the IPv4 length (12) or writing only one address (16/18 bytes).
Common situations: Proxies that hardcode IPv4 header sizes and get an IPv6 upstream connection; hand-rolled test harnesses; buggy header builders in custom TCP middleware.
Related errors
- %w: TCP4 with IPv6 address
- %w: TCP6 with IPv4 address
- %w: unsupported address family 0x%02x
- IPv4 address data too short: %d bytes
- failed to read protocol version: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/39be6c341c29a155.
Report an issue: GitHub.