{"record":{"id":"8891b372453ee245","repo":"nats-io/nats-server","slug":"failed-to-read-ipv4-address-data-w","errorCode":null,"errorMessage":"failed to read IPv4 address data: %w","messagePattern":"failed to read IPv4 address data: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/client_proxyproto.go","lineNumber":389,"sourceCode":"\t\t\t\treturn nil, fmt.Errorf(\"failed to discard UNSPEC address address data: %w\", err)\n\t\t\t}\n\t\t}\n\t\treturn nil, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%w: unsupported address family 0x%02x\", errProxyProtoUnsupported, family)\n\t}\n\treturn addr, err\n}\n\n// parseIPv4Addr parses IPv4 address data from PROXY protocol header\nfunc parseIPv4Addr(conn net.Conn, addrLen uint16) (*proxyProtoAddr, error) {\n\t// IPv4: 4 (src IP) + 4 (dst IP) + 2 (src port) + 2 (dst port) = 12 bytes minimum\n\tif addrLen < proxyProtoAddrSizeIPv4 {\n\t\treturn nil, fmt.Errorf(\"IPv4 address data too short: %d bytes\", addrLen)\n\t}\n\taddrData := make([]byte, addrLen)\n\tif _, err := io.ReadFull(conn, addrData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read IPv4 address data: %w\", err)\n\t}\n\treturn &proxyProtoAddr{\n\t\tsrcIP:   net.IP(addrData[0:4]),\n\t\tdstIP:   net.IP(addrData[4:8]),\n\t\tsrcPort: binary.BigEndian.Uint16(addrData[8:10]),\n\t\tdstPort: binary.BigEndian.Uint16(addrData[10:12]),\n\t}, nil\n}\n\n// parseIPv6Addr parses IPv6 address data from PROXY protocol header\nfunc parseIPv6Addr(conn net.Conn, addrLen uint16) (*proxyProtoAddr, error) {\n\t// IPv6: 16 (src IP) + 16 (dst IP) + 2 (src port) + 2 (dst port) = 36 bytes minimum\n\tif addrLen < proxyProtoAddrSizeIPv6 {\n\t\treturn nil, fmt.Errorf(\"IPv6 address data too short: %d bytes\", addrLen)\n\t}\n\taddrData := make([]byte, addrLen)\n\tif _, err := io.ReadFull(conn, addrData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read IPv6 address data: %w\", err)","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L371-L407","documentation":"The v2 header declared a valid (>=12 byte) IPv4 address length, but reading that many bytes from the connection with io.ReadFull failed (connection closed, timeout, or reset) before the full address payload arrived. The underlying I/O error is wrapped in the %w so the cause is preserved.","triggerScenarios":"Client disconnects immediately after sending the PROXY header signature and length but before the 12-byte address data; network timeout mid-header; LB health-check probes that send a partial header then close.","commonSituations":"Health checks / port scanners hitting a PROXY-enabled port with half-formed headers; flaky mobile clients; LB connection draining between header write and body write.","solutions":["Ensure the upstream proxy writes the complete PROXY header atomically (single write) so it is never split by disconnects.","Check whether clients/probes are connecting to a PROXY-enabled listener without speaking PROXY protocol and move them to a non-PROXY listener.","Handle this as a transient connection error: retry the connection; use errors.Is/As on the wrapped cause to distinguish io.EOF/io.ErrUnexpectedEOF from timeouts."],"exampleFix":"// before: partial writes from proxy\ntcpConn.Write(headerSig)\n// peer may disconnect here\n// after\nbuf := buildFullV2Header(addr)\ntcpConn.Write(buf) // one atomic write","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isTransientHeaderRead(err error) bool {\n    return errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, os.ErrDeadlineExceeded)\n}","tryCatchPattern":"_, err := connectWithProxy()\nif err != nil && strings.Contains(err.Error(), \"failed to read IPv4 address data\") {\n    if isTransientHeaderRead(errors.Unwrap(err)) {\n        time.Sleep(backoff)\n        return connectWithProxy() // retry transient disconnect\n    }\n}","preventionTips":["Send the entire PROXY header in one write() from the proxy","Exclude health-check probes from PROXY-enabled ports","Keep connect timeouts on the proxy path generous enough for the full header exchange"],"tags":["network","proxy-protocol","io"],"backgroundTag":"connection-closed-mid-handshake","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}