nats-io/nats-server · warning
unsupported PROXY protocol version: %d
Error message
unsupported PROXY protocol version: %d
What it means
This error is returned from the default branch of readProxyProtoHeader's version switch when detectProxyProtoVersion reports a version that is neither 1 nor 2. In the current implementation detectProxyProtoVersion only returns 1, 2, or an error, so this branch is a defensive guard for future/unknown protocol versions rather than a code path reachable through the public detection logic. It formats the detected version number into the message for diagnostics.
Source
Thrown at server/client_proxyproto.go:282
}
// Verify full signature
fullSig := string(firstBytes) + string(remaining)
if fullSig != proxyProtoV2Sig {
return nil, nil, fmt.Errorf("%w: invalid signature", errProxyProtoInvalid)
}
// Read rest of header: ver/cmd, fam/proto, addr-len (4 bytes)
header := make([]byte, 4)
if _, err := io.ReadFull(conn, header); err != nil {
return nil, nil, fmt.Errorf("failed to read v2 header: %w", err)
}
// Continue with parsing
addr, err := parseProxyProtoV2Header(conn, header)
return addr, nil, err
default:
return nil, nil, fmt.Errorf("unsupported PROXY protocol version: %d", version)
}
}
// readProxyProtoV2Header is kept for backward compatibility and direct testing.
// It reads and parses a PROXY protocol v2 header from the connection.
// If the command is LOCAL (health check), it returns nil for addr and no error.
// If the command is PROXY, it returns the parsed address information.
// The connection must be fresh (no data read yet).
func readProxyProtoV2Header(conn net.Conn) (*proxyProtoAddr, error) {
// Set read deadline to prevent hanging on slow/malicious clients
if err := conn.SetReadDeadline(time.Now().Add(proxyProtoReadTimeout)); err != nil {
return nil, err
}
defer conn.SetReadDeadline(time.Time{})
// Read fixed header (16 bytes)
header := make([]byte, proxyProtoV2HeaderSize)
if _, err := io.ReadFull(conn, header); err != nil {View on GitHub (pinned to 3a66a489d2)
Solutions
- Confirm the sender's PROXY protocol version; only v1 (text 'PROXY ...') and v2 (binary signature) are supported by this parser.
- If you modified detectProxyProtoVersion, add a corresponding case to the switch in readProxyProtoHeader or map the new version onto the existing v1/v2 parsers.
- Upstream: this is defensive code; if you see it in production without local modifications, capture the connection bytes and report the sender's protocol output.
Example fix
// before: detectProxyProtoVersion returns 3 for an experimental format
// after: return errProxyProtoUnrecognized for unknown versions so the
// unrecognized-format path (with byte replay) handles it instead
// if sig is neither v1 prefix nor v2 sig prefix { return 0, header, errProxyProtoUnrecognized } Defensive patterns
Strategy: fallback
Type guard
func isUnsupportedVersion(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "unsupported PROXY protocol version:")
} Try / catch
addr, extra, err := readProxyProtoHeader(conn)
if err != nil {
if isUnsupportedVersion(err) {
// log version number from message; fall back to non-PROXY handling or reject
conn.Close()
return
}
return
} Prevention
- Only v1 and v2 exist in practice; keep senders on standard PROXY protocol versions.
- If you extend detectProxyProtoVersion, update the switch in readProxyProtoHeader in the same change.
- Prefer returning errProxyProtoUnrecognized from detection so unknown formats hit the replay-capable path.
- Add a unit test covering the default branch whenever the version detection logic changes.
When it happens
Trigger: Only reachable if detectProxyProtoVersion is changed or extended to return a version other than 1 or 2 without readProxyProtoHeader being updated; the corresponding test (TestClientProxyProtoV1ParseUnknown et al.) exercises the surrounding switch but this branch itself would require a hypothetical version like 3.
Common situations: Future PROXY protocol revisions or custom forks emitting a new version byte; custom modifications to detectProxyProtoVersion; third-party code vendoring the parser and adding a version case upstream.
Related errors
- ErrBadVersion
- failed to read protocol version: %w
- failed to read v1 line: %w
- %w: v1 line too long
- %w: invalid v1 format
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/d67f7b5cf3ae737b.
Report an issue: GitHub.