nats-io/nats-server · error

unknown PROXY protocol command: 0x%02x

Error message

unknown PROXY protocol command: 0x%02x

What it means

The PROXY protocol v2 spec defines only two commands: LOCAL (0x0) and PROXY (0x1). This error is raised when the command nibble of the ver/cmd byte holds any other value, meaning the sender produced a header the library does not recognize. It is returned as-is (not wrapped in a sentinel), so callers must string-match rather than errors.Is.

Source

Thrown at server/client_proxyproto.go:350

	// Parse address length (big-endian uint16)
	addrLen := binary.BigEndian.Uint16(header[2:4])

	// Handle LOCAL command (health check)
	if command == proxyProtoCmdLocal {
		// For LOCAL, we should skip the address data if any
		if addrLen > 0 {
			// Discard the address data
			if _, err := io.CopyN(io.Discard, conn, int64(addrLen)); err != nil {
				return nil, fmt.Errorf("failed to discard LOCAL command address data: %w", err)
			}
		}
		return nil, nil // nil addr indicates LOCAL command
	}

	// Handle PROXY command
	if command != proxyProtoCmdProxy {
		return nil, fmt.Errorf("unknown PROXY protocol command: 0x%02x", command)
	}

	// Validate protocol (we only support STREAM/TCP)
	if protocol != proxyProtoProtoStream {
		return nil, fmt.Errorf("%w: only STREAM protocol supported", errProxyProtoUnsupported)
	}

	// Parse address data based on family
	var addr *proxyProtoAddr
	var err error
	switch family {
	case proxyProtoFamilyInet:
		addr, err = parseIPv4Addr(conn, addrLen)
	case proxyProtoFamilyInet6:
		addr, err = parseIPv6Addr(conn, addrLen)
	case proxyProtoFamilyUnspec:
		// UNSPEC family with PROXY command is valid but rare
		// Just skip the address data

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Fix or update the upstream sender to emit only LOCAL (0x0) or PROXY (0x1) commands
  2. Dump the ver/cmd byte to identify which value is being sent
  3. Check the proxy vendor's documentation for nonstandard command extensions
  4. If the command is legitimate per a newer spec revision, patch parseProxyProtoV2Header to handle it

Example fix

// before (sender)
verCmd := 0x22 // command 0x2 unsupported
// after
verCmd := 0x21 // command PROXY (0x1)
Defensive patterns

Strategy: try-catch

Validate before calling

// Only 0x0 (LOCAL) and 0x1 (PROXY) are valid command nibbles
if c := hdr[12]&0x0F; c > 0x1 {
    return fmt.Errorf("invalid PROXY v2 command 0x%x", c)
}

Type guard

func isKnownProxyCmd(b byte) bool { c := b&0x0F; return c == 0x0 || c == 0x1 }

Try / catch

addr, err := readProxyProtoHeader(conn)
if err != nil {
    if strings.HasPrefix(err.Error(), "unknown PROXY protocol command") {
        // log ver/cmd byte, close connection — sender is non-conformant
        conn.Close()
        return
    }
    return err
}

Prevention

When it happens

Trigger: A peer sends a valid v2 signature but the ver/cmd low nibble is >= 0x2, e.g. command bits 0x2-0xF from a buggy sender, bit-flipped corruption, or a custom/nonstandard sender.

Common situations: Firmware bugs in proxies emitting reserved command values; memory/bit corruption on the wire; handcrafted clients testing the parser; protocol extensions the server has not implemented.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/b0845b51eaf28c08. Report an issue: GitHub.