{"record":{"id":"66ed8cfc15f5603d","repo":"nats-io/nats-server","slug":"w-only-stream-protocol-supported","errorCode":null,"errorMessage":"%w: only STREAM protocol supported","messagePattern":"%w: only STREAM protocol supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/client_proxyproto.go","lineNumber":355,"sourceCode":"\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\n\tswitch family {\n\tcase proxyProtoFamilyInet:\n\t\taddr, err = parseIPv4Addr(conn, addrLen)\n\tcase proxyProtoFamilyInet6:\n\t\taddr, err = parseIPv6Addr(conn, addrLen)\n\tcase proxyProtoFamilyUnspec:\n\t\t// UNSPEC family with PROXY command is valid but rare\n\t\t// Just skip the address data\n\t\tif addrLen > 0 {\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 UNSPEC address address data: %w\", err)\n\t\t\t}\n\t\t}","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L337-L373","documentation":"PROXY protocol v2 distinguishes datagram (DGRAM, 0x1) and stream (STREAM, 0x0) transports via the low nibble of the fam/proto byte. This server only accepts TCP streams, so a header declaring DGRAM (UDP) is rejected with errProxyProtoUnsupported (matchable via errors.Is).","triggerScenarios":"A sender transmits a v2 header with protocol nibble = 0x1 (DGRAM), typically from a UDP-mode PROXY header emitter, over a TCP connection the server accepts.","commonSituations":"Proxy configured in UDP proxying mode forwarding headers to a TCP-only backend; miscopied config where the frontend protocol (UDP) doesn't match the backend (TCP); custom senders defaulting to DGRAM.","solutions":["Reconfigure the proxy frontend/backend so PROXY v2 headers are emitted for TCP (STREAM) traffic","Ensure the header's fam/proto byte uses 0x0 in the protocol nibble for TCP","If UDP support is needed, extend parseProxyProtoV2Header to accept DGRAM and handle the address payload"],"exampleFix":"// before (HAProxy)\nbind :8475 proto udp\n// after\nbind :8475 proto tcp ... send-proxy-v2","handlingStrategy":"validation","validationCode":"// STREAM = 0x0 in the protocol nibble of the fam/proto byte\nif p := hdr[13]&0x0F; p != 0x0 {\n    return fmt.Errorf(\"only STREAM supported, got 0x%x\", p)\n}","typeGuard":"func isStreamProto(famProto byte) bool { return famProto&0x0F == 0x0 }","tryCatchPattern":"addr, err := readProxyProtoHeader(conn)\nif err != nil {\n    if errors.Is(err, errProxyProtoUnsupported) {\n        // non-TCP traffic to a TCP-only backend: reject and close\n        conn.Close()\n        return\n    }\n    return err\n}","preventionTips":["Match proxy frontend transport (tcp vs udp) to the backend before enabling send-proxy-v2","Only enable PROXY protocol on TCP listeners","Document that this server is TCP/STREAM-only","Validate fam/proto byte 0x00/0x10/0x20/0x30 (all STREAM) in sender tests"],"tags":["proxy-protocol","unsupported-protocol","udp","tcp"],"backgroundTag":"unsupported-proxy-protocol","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}