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

  1. Correct the proxy to declare 36 bytes of address data for AF_INET6 v2 headers.
  2. Prefer forcing IPv4 upstream (set resolver/address family) so the proxy emits AF_INET headers if it only supports them correctly.
  3. 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

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


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/39be6c341c29a155. Report an issue: GitHub.