{"record":{"id":"682365b10828cfb1","repo":"nats-io/nats-server","slug":"invalid-source-port-w","errorCode":null,"errorMessage":"invalid source port: %w","messagePattern":"invalid source port: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/client_proxyproto.go","lineNumber":200,"sourceCode":"\t}\n\n\t// Must have exactly 5 parts: protocol, src-ip, dst-ip, src-port, dst-port\n\tif len(parts) != 5 {\n\t\treturn nil, nil, fmt.Errorf(\"%w: invalid v1 format\", errProxyProtoInvalid)\n\t}\n\n\tprotocol := parts[0]\n\tsrcIP := net.ParseIP(parts[1])\n\tdstIP := net.ParseIP(parts[2])\n\n\tif srcIP == nil || dstIP == nil {\n\t\treturn nil, nil, fmt.Errorf(\"%w: invalid address\", errProxyProtoInvalid)\n\t}\n\n\t// Parse ports\n\tsrcPort, err := strconv.ParseUint(parts[3], 10, 16)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid source port: %w\", err)\n\t}\n\n\tdstPort, err := strconv.ParseUint(parts[4], 10, 16)\n\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) {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/client_proxyproto.go#L182-L218","documentation":"The v1 header's source-port field could not be parsed by strconv.ParseUint base 10 with bit size 16. The field was empty, non-numeric, or outside 0-65535. The server wraps the strconv error and aborts the connection.","triggerScenarios":"Header contains a bad source port such as 'PROXY TCP4 192.0.2.1 198.51.100.7 abc 4222\\r\\n', a negative port, or a port above 65535 like '70000'.","commonSituations":"Proxy emitting port placeholders or variable interpolation failures (e.g. empty template slot); corrupted stream mixing header bytes; hand-written client using hex or string port values.","solutions":["Ensure the source-port field is a decimal number in 0-65535","Check the proxy template for unfilled/interpolated port variables","Inspect the raw header bytes to identify what text landed in the port field","Fix test clients to format ports with %d, not strings"],"exampleFix":"// before\n\"PROXY TCP4 192.0.2.1 198.51.100.7 abc 4222\\r\\n\"\n// after\n\"PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\\r\\n\"","handlingStrategy":"validation","validationCode":"sport, err := strconv.ParseUint(srcPortStr, 10, 16)\nif err != nil {\n    return fmt.Errorf(\"refusing to send PROXY header: bad source port %q\", srcPortStr)\n}","typeGuard":"func validPort(s string) bool {\n    p, err := strconv.ParseUint(s, 10, 16)\n    return err == nil && p > 0\n}","tryCatchPattern":"_, _, err := readProxyProtoHeader(conn)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid source port\") {\n        log.Printf(\"peer sent bad PROXY src port: %v\", err)\n        return\n    }\n    return err\n}","preventionTips":["Format ports with %d (decimal), never service names or hex","Check proxy templates render port variables correctly","Range-check ports to 1-65535 before sending"],"tags":["proxy-protocol","network","port","nats"],"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"}