nats-io/nats-server · error
invalid dest port: %w
Error message
invalid dest port: %w
What it means
The v1 header's destination-port field could not be parsed by strconv.ParseUint base 10 with bit size 16. The field was empty, non-numeric, negative, or above 65535. The server wraps the strconv error and aborts the connection.
Source
Thrown at server/client_proxyproto.go:205
}
protocol := parts[0]
srcIP := net.ParseIP(parts[1])
dstIP := net.ParseIP(parts[2])
if srcIP == nil || dstIP == nil {
return nil, nil, fmt.Errorf("%w: invalid address", errProxyProtoInvalid)
}
// Parse ports
srcPort, err := strconv.ParseUint(parts[3], 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("invalid source port: %w", err)
}
dstPort, err := strconv.ParseUint(parts[4], 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("invalid dest port: %w", err)
}
// Validate protocol matches IP version. The textual form determines the
// family: TCP4 requires dotted-quad addresses, TCP6 requires IPv6
// addresses. IPv4-mapped IPv6 addresses (e.g. "::ffff:192.0.2.1") are
// valid for TCP6 since dual-stack proxies can emit those for IPv4
// clients on IPv6 sockets, matching the v2 parser behavior.
srcIsV6 := strings.Contains(parts[1], ":")
dstIsV6 := strings.Contains(parts[2], ":")
if protocol == proxyProtoV1TCP4 && (srcIsV6 || dstIsV6) {
return nil, nil, fmt.Errorf("%w: TCP4 with IPv6 address", errProxyProtoInvalid)
}
if protocol == proxyProtoV1TCP6 && (!srcIsV6 || !dstIsV6) {
return nil, nil, fmt.Errorf("%w: TCP6 with IPv4 address", errProxyProtoInvalid)
}
if protocol != proxyProtoV1TCP4 && protocol != proxyProtoV1TCP6 {
return nil, nil, fmt.Errorf("%w: invalid protocol %s", errProxyProtoInvalid, protocol)
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Ensure the destination-port field is a decimal number in 0-65535
- Fix the proxy configuration to use the numeric listen port (e.g. 4222) not a service name
- Inspect the raw header with tcpdump to see the offending field
- Correct test fixtures to use numeric ports
Example fix
// before "PROXY TCP4 192.0.2.1 198.51.100.7 35646 https\r\n" // after "PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\r\n"
Defensive patterns
Strategy: validation
Validate before calling
dport, err := strconv.ParseUint(dstPortStr, 10, 16)
if err != nil {
return fmt.Errorf("refusing to send PROXY header: bad dest port %q", dstPortStr)
} Type guard
func validPort(s string) bool {
p, err := strconv.ParseUint(s, 10, 16)
return err == nil && p > 0
} Try / catch
_, _, err := readProxyProtoHeader(conn)
if err != nil {
if strings.Contains(err.Error(), "invalid dest port") {
log.Printf("peer sent bad PROXY dst port: %v", err)
return
}
return err
} Prevention
- Use the numeric listen port (e.g. 4222), not a service name like 'nats'
- Ensure template variables for the destination port are always populated
- Range-check ports to 1-65535 before sending
When it happens
Trigger: Header contains a bad destination port such as 'PROXY TCP4 192.0.2.1 198.51.100.7 35646 https\r\n' or '65536'.
Common situations: Proxy configured to emit a service name instead of a numeric port; template variable left unfilled; corruption from a misbehaving intermediary rewriting the header.
Related errors
- invalid source port: %w
- %w: v1 line too long
- %w: invalid v1 format
- %w: invalid address
- %w: TCP4 with IPv6 address
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/6f091d04da02ce8d.
Report an issue: GitHub.