{"record":{"id":"512d605b6fde1bcf","repo":"nats-io/nats-server","slug":"w-invalid-protocol-s","errorCode":null,"errorMessage":"%w: invalid protocol %s","messagePattern":"%w: invalid protocol (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/client_proxyproto.go","lineNumber":222,"sourceCode":"\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid dest port: %w\", err)\n\t}\n\n\t// Validate protocol matches IP version. The textual form determines the\n\t// family: TCP4 requires dotted-quad addresses, TCP6 requires IPv6\n\t// addresses. IPv4-mapped IPv6 addresses (e.g. \"::ffff:192.0.2.1\") are\n\t// valid for TCP6 since dual-stack proxies can emit those for IPv4\n\t// clients on IPv6 sockets, matching the v2 parser behavior.\n\tsrcIsV6 := strings.Contains(parts[1], \":\")\n\tdstIsV6 := strings.Contains(parts[2], \":\")\n\tif protocol == proxyProtoV1TCP4 && (srcIsV6 || dstIsV6) {\n\t\treturn nil, nil, fmt.Errorf(\"%w: TCP4 with IPv6 address\", errProxyProtoInvalid)\n\t}\n\tif protocol == proxyProtoV1TCP6 && (!srcIsV6 || !dstIsV6) {\n\t\treturn nil, nil, fmt.Errorf(\"%w: TCP6 with IPv4 address\", errProxyProtoInvalid)\n\t}\n\tif protocol != proxyProtoV1TCP4 && protocol != proxyProtoV1TCP6 {\n\t\treturn nil, nil, fmt.Errorf(\"%w: invalid protocol %s\", errProxyProtoInvalid, protocol)\n\t}\n\n\treturn &proxyProtoAddr{\n\t\tsrcIP:   srcIP,\n\t\tsrcPort: uint16(srcPort),\n\t\tdstIP:   dstIP,\n\t\tdstPort: uint16(dstPort),\n\t}, remaining, nil\n}\n\n// readProxyProtoHeader reads and parses PROXY protocol (v1 or v2) from the connection.\n// Automatically detects version and routes to appropriate parser.\n// If the command is LOCAL/UNKNOWN (health check), it returns nil for addr and no error.\n// If the command is PROXY, it returns the parsed address information.\n// It also returns any bytes that were read past the v1 header terminator so the\n// caller can replay them into the normal client parser.\n// The connection must be fresh (no data read yet).\nfunc readProxyProtoHeader(conn net.Conn) (*proxyProtoAddr, []byte, error) {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L204-L240","documentation":"The first field of the v1 header was neither TCP4, TCP6, nor the earlier-handled UNKNOWN. The PROXY protocol v1 spec only defines those keywords, so any other protocol token (e.g. UDP4, TCP, or garbage) makes the header invalid and the server rejects it with errProxyProtoInvalid, including the offending value in the message.","triggerScenarios":"Header like 'PROXY UDP4 192.0.2.1 198.51.100.7 35646 4222\\r\\n' or 'PROXY tcp4 ...' (lowercase); reached only when there are exactly 5 fields and the keyword is not TCP4/TCP6/UNKNOWN.","commonSituations":"Proxy supporting UDP proxy-protocol extensions not supported by this server; case-sensitivity bugs in custom senders; test fixtures with typos like 'PROXY TCP 192.0.2.1 ...'.","solutions":["Change the sender to emit only TCP4 or TCP6 (or UNKNOWN for health checks)","Fix case-sensitivity: the keyword must be uppercase TCP4/TCP6","If you need UDP proxying, this server does not support it via PROXY protocol v1 - use a supported transport","Correct typo'd protocol keywords in test clients and templates"],"exampleFix":"// before\n\"PROXY UDP4 192.0.2.1 198.51.100.7 35646 4222\\r\\n\"\n// after\n\"PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\\r\\n\"","handlingStrategy":"validation","validationCode":"if proto != \"TCP4\" && proto != \"TCP6\" && proto != \"UNKNOWN\" {\n    return fmt.Errorf(\"unsupported v1 protocol keyword %q; use TCP4/TCP6/UNKNOWN\", proto)\n}","typeGuard":"func isKnownV1Protocol(s string) bool {\n    switch s {\n    case \"TCP4\", \"TCP6\", \"UNKNOWN\":\n        return true\n    }\n    return false\n}","tryCatchPattern":"_, _, err := readProxyProtoHeader(conn)\nif err != nil {\n    if errors.Is(err, errProxyProtoInvalid) && strings.Contains(err.Error(), \"invalid protocol\") {\n        log.Printf(\"peer sent unsupported v1 protocol keyword: %v\", err)\n        return\n    }\n    return err\n}","preventionTips":["Only emit uppercase TCP4, TCP6, or UNKNOWN","This server does not accept UDP keywords (UDP4/UDP6) in v1 headers","Validate sender templates with a keyword whitelist before deploy"],"tags":["proxy-protocol","network","nats","malformed-input"],"backgroundTag":"proxy-protocol-invalid-header","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}