VictoriaMetrics/VictoriaMetrics · error
cannot read ipv6 address from proxy protocol block with the
Error message
cannot read ipv6 address from proxy protocol block with the length %d bytes; expected at least 36 bytes
What it means
The proxy protocol v2 header declared a PROXY command with an IPv6 (AF_INET6) address block, but the block payload received was shorter than the 36 bytes needed for a 16-byte IPv6 address + 16-byte destination address + 2+2 bytes of ports. The library throws this because parsing the block would read past its end, so the sender's header length field does not match the actual address data sent.
Source
Thrown at lib/netutil/proxyprotocol.go:129
// Proxy LOCAL command. Ignore the protocol block. The real sender address should be used.
return nil, nil
case 1:
// Parse the protocol block according to the family.
switch family {
case 1:
// ipv4 (aka AF_INET)
if len(bb.B) < 12 {
return nil, fmt.Errorf("cannot read ipv4 address from proxy protocol block with the length %d bytes; expected at least 12 bytes", len(bb.B))
}
remoteAddr := &net.TCPAddr{
IP: net.IPv4(bb.B[0], bb.B[1], bb.B[2], bb.B[3]),
Port: int(binary.BigEndian.Uint16(bb.B[8:10])),
}
return remoteAddr, nil
case 2:
// ipv6 (aka AF_INET6)
if len(bb.B) < 36 {
return nil, fmt.Errorf("cannot read ipv6 address from proxy protocol block with the length %d bytes; expected at least 36 bytes", len(bb.B))
}
var ipv6Addr net.IP
ipv6Addr = append(ipv6Addr, bb.B[:16]...)
remoteAddr := &net.TCPAddr{
IP: ipv6Addr,
Port: int(binary.BigEndian.Uint16(bb.B[32:34])),
}
return remoteAddr, nil
default:
return nil, fmt.Errorf("the proxy protocol implementation doesn't support protocol family %d; supported values: 1, 2", family)
}
default:
return nil, fmt.Errorf("the proxy protocol implementation doesn't support command %d; supported values: 0, 1", command)
}
}
const v2Identifier = "\r\n\r\n\x00\r\nQUIT\n"
View on GitHub (pinned to 5079fb58f1)
Solutions
- Fix the upstream proxy so it emits a correct proxy protocol v2 header: for AF_INET6 the address block must be 36 bytes (16 src addr + 16 dst addr + 2 src port + 2 dst port) and the header length field must equal the block size plus any TLVs.
- Verify the sender is actually speaking binary v2 (starts with the 12-byte signature \r\n\r\n\x00\r\nQUIT\n), not v1 text ('PROXY TCP6 ...') mixed into a v2 stream.
- Capture the first bytes the client sends (tcpdump or the logged header %q in the sibling error) to confirm which proxy is misconfigured.
- If the sender only sends health-check LOCAL commands, ensure it uses command=0 (proto 0), which skips block parsing entirely and cannot hit this error.
Example fix
// before (misconfigured HAProxy v2 sender emits a 16-byte block for IPv6) // signature ... cmd=0x21, fam=0x22, len=0x0010 -> too short // after // signature ... cmd=0x21, fam=0x22, len=0x0024 -> 36-byte IPv6 address block
Defensive patterns
Strategy: validation
Validate before calling
// Before sending (sender side) or testing (receiver side), assert the v2 address block size:
func validV2IPv6Block(block []byte) bool { return len(block) >= 36 }
// Sender: hdr length field must equal len(block):
// binary.BigEndian.PutUint16(hdr[14:16], uint16(len(block))) // 36 for AF_INET6 Type guard
func isSupportedProxyFamily(family byte) bool { return family == 1 || family == 2 }
func hasIPv6ProxyBlock(block []byte) bool { return len(block) >= 36 } Prevention
- Always set the v2 header length field to the exact address-block size (36 bytes for IPv6, 12 for IPv4).
- Use a maintained proxy-protocol library (e.g. github.com/haproxytech/proxy-protocol or officem oplib) instead of hand-packing headers.
- Integration-test with real HAProxy/NGINX send-proxy-v2 before production.
- Monitor VictoriaMetrics logs for 'proxy protocol' errors after load balancer config changes.
When it happens
Trigger: A client/load balancer sends a proxy protocol v2 header with version/command byte indicating command=1 (PROXY) and family nibble=2 (IPv6), but the length field at bytes 14-15 (blockLen) is under 36 or the peer closes/sends fewer bytes, so io.ReadFull returns a short block and len(bb.B) < 36 in readProxyProto (lib/netutil/proxyprotocol.go:128-129).
Common situations: A misconfigured HAProxy/NGINX/AWS NLB sending truncated or malformed v2 binary headers; a proxy sending v1 (text) header fragments that get misframed; writing a custom proxy-protocol sender that sets an incorrect payload length; network truncation between proxy and VictoriaMetrics listener with -proxyProtocolAddr enabled.
Related errors
- the proxy protocol implementation doesn't support protocol f
- the proxy protocol implementation doesn't support command %d
- %w; try -enableTCP6 command-line flag for dialing ipv6 addre
- legacy handshake error: %w
- cannot read hello: %w
AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03).
Data as JSON: /api/errors/36fd6908e128fc69.
Report an issue: GitHub.