{"record":{"id":"674438ddfa43a5ae","repo":"nats-io/nats-server","slug":"failed-to-read-ipv6-address-data-w","errorCode":null,"errorMessage":"failed to read IPv6 address data: %w","messagePattern":"failed to read IPv6 address data: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/client_proxyproto.go","lineNumber":407,"sourceCode":"\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)\n\t}\n\treturn &proxyProtoAddr{\n\t\tsrcIP:   net.IP(addrData[0:16]),\n\t\tdstIP:   net.IP(addrData[16:32]),\n\t\tsrcPort: binary.BigEndian.Uint16(addrData[32:34]),\n\t\tdstPort: binary.BigEndian.Uint16(addrData[34:36]),\n\t}, nil\n}\n","sourceCodeStart":389,"sourceCodeEnd":416,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L389-L416","documentation":"The AF_INET6 header declared a valid (>=36 byte) address length, but io.ReadFull could not read that many bytes from the connection, so the IPv6 address payload arrived incomplete. The wrapped underlying I/O error is preserved via %w.","triggerScenarios":"Connection closed or timed out after the v2 header was partially written; the peer sent only the 16-byte signature + length and then dropped; scanner/probe sent a truncated header.","commonSituations":"Health checks against a PROXY listener; unstable networks between LB and NATS; proxies split writes across packets and the client disconnects between them.","solutions":["Have the proxy send the whole PROXY v2 header in one write to reduce the partial-read window.","Treat as transient: reconnect; inspect the wrapped error with errors.Is(err, io.ErrUnexpectedEOF) vs timeout to decide.","Verify nothing between LB and server (idle timeouts, security appliances) is cutting short connections immediately after header write."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isHeaderTruncation(err error) bool {\n    return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, net.ErrClosed)\n}","tryCatchPattern":"if err != nil {\n    var terr net.Error\n    if errors.As(err, &terr) && terr.Timeout() {\n        return retryWithBackoff()\n    }\n    if strings.Contains(err.Error(), \"failed to read IPv6 address data\") {\n        return reconnect() // peer dropped mid-header\n    }\n}","preventionTips":["Write the full PROXY v2 header atomically from the proxy side","Monitor for RST/close spikes between LB and server","Avoid aggressive idle timeouts that can sever connections right after the header"],"tags":["network","io","proxy-protocol"],"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"}