{"record":{"id":"c35e78e3727e9726","repo":"nats-io/nats-server","slug":"failed-to-discard-local-command-address-data-w","errorCode":null,"errorMessage":"failed to discard LOCAL command address data: %w","messagePattern":"failed to discard LOCAL command address data: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/client_proxyproto.go","lineNumber":342,"sourceCode":"\tif version != proxyProtoV2Ver {\n\t\treturn nil, fmt.Errorf(\"%w: invalid version 0x%02x\", errProxyProtoInvalid, version)\n\t}\n\n\t// Parse address family and protocol\n\tfamProto := header[1]\n\tfamily := famProto & proxyProtoFamilyMask\n\tprotocol := famProto & proxyProtoProtoMask\n\n\t// Parse address length (big-endian uint16)\n\taddrLen := binary.BigEndian.Uint16(header[2:4])\n\n\t// Handle LOCAL command (health check)\n\tif command == proxyProtoCmdLocal {\n\t\t// For LOCAL, we should skip the address data if any\n\t\tif addrLen > 0 {\n\t\t\t// Discard the address data\n\t\t\tif _, err := io.CopyN(io.Discard, conn, int64(addrLen)); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to discard LOCAL command address data: %w\", err)\n\t\t\t}\n\t\t}\n\t\treturn nil, nil // nil addr indicates LOCAL command\n\t}\n\n\t// Handle PROXY command\n\tif command != proxyProtoCmdProxy {\n\t\treturn nil, fmt.Errorf(\"unknown PROXY protocol command: 0x%02x\", command)\n\t}\n\n\t// Validate protocol (we only support STREAM/TCP)\n\tif protocol != proxyProtoProtoStream {\n\t\treturn nil, fmt.Errorf(\"%w: only STREAM protocol supported\", errProxyProtoUnsupported)\n\t}\n\n\t// Parse address data based on family\n\tvar addr *proxyProtoAddr\n\tvar err error","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L324-L360","documentation":"After a LOCAL command (health check) is parsed, the library must still consume addrLen bytes of address payload from the connection so the stream stays in sync. This error wraps whatever failure occurred while discarding those bytes (io.CopyN error, usually EOF/timeout/reset).","triggerScenarios":"Peer sends a v2 header declaring command LOCAL with addrLen>0 but closes, times out (proxyProtoReadDeadline), or resets the connection before the declared address bytes can be read; or sends fewer bytes than advertised in the length field.","commonSituations":"Health checker abruptly closing after sending a LOCAL header; a truncated packet from a buggy proxy; network drop mid-header; aggressive client timeouts.","solutions":["Check the wrapped error: EOF/unexpected EOF means the sender truncated the header payload","Ensure health-check senders transmit the full address section matching the declared length","Increase the read deadline if the sender is slow rather than broken","Retry the connection — this is typically transient on flaky networks"],"exampleFix":"// before: sender sends LOCAL header claiming 12 bytes but closes early\nconn.Close()\n// after: send the full advertised payload\nwrite(header); write(addrBytes) // addrBytes len == addrLen","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"addr, err := readProxyProtoHeader(conn)\nif err != nil && strings.Contains(err.Error(), \"failed to discard LOCAL command address data\") {\n    if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(context.DeadlineExceeded, err) {\n        return errRetryable\n    }\n    return err\n}","preventionTips":["Ensure LOCAL health-check senders include the full address section they declare","Set a realistic read deadline for slow networks","Monitor for unexpected EOF spikes indicating truncated headers","Keep proxy firmware updated — old versions truncate LOCAL payloads"],"tags":["proxy-protocol","network","io"],"backgroundTag":"proxy-protocol-truncated-header","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}