fatedier/frp · error

selected UDP packet codec was not advertised by client: %s

Error message

selected UDP packet codec was not advertised by client: %s

What it means

Thrown by ValidateServerHelloForClient when the ServerHello selects UDP packet codec "binary" but the client never advertised that codec in ClientHello.Capabilities.Message.UDPPacketCodecs. This guards against a server unilaterally enabling a feature the client did not offer, which would break the client's ability to decode UDP packets.

Source

Thrown at pkg/proto/wire/crypto.go:102

		return fmt.Errorf("invalid crypto client random length %d, want %d", len(c.ClientRandom), CryptoRandomSize)
	}
	if _, ok := SelectAEADAlgorithm(c.Algorithms); !ok {
		return fmt.Errorf("no supported crypto algorithm")
	}
	return nil
}

func ValidateServerHelloForClient(clientHello ClientHello, serverHello ServerHello) error {
	if serverHello.Selected.Message.Codec != MessageCodecJSON {
		return fmt.Errorf("unsupported selected message codec: %s", serverHello.Selected.Message.Codec)
	}
	udpPacketCodec := serverHello.Selected.Message.UDPPacketCodec
	if udpPacketCodec != "" {
		if udpPacketCodec != UDPPacketCodecBinary {
			return fmt.Errorf("unsupported selected UDP packet codec: %s", udpPacketCodec)
		}
		if !Supports(clientHello.Capabilities.Message.UDPPacketCodecs, udpPacketCodec) {
			return fmt.Errorf("selected UDP packet codec was not advertised by client: %s", udpPacketCodec)
		}
	}
	cryptoSelection := serverHello.Selected.Crypto
	if !IsSupportedAEADAlgorithm(cryptoSelection.Algorithm) {
		return fmt.Errorf("unknown selected crypto algorithm: %s", cryptoSelection.Algorithm)
	}
	if !Supports(clientHello.Capabilities.Crypto.Algorithms, cryptoSelection.Algorithm) {
		return fmt.Errorf("selected crypto algorithm was not advertised by client: %s", cryptoSelection.Algorithm)
	}
	if len(cryptoSelection.ServerRandom) != CryptoRandomSize {
		return fmt.Errorf("invalid crypto server random length %d, want %d", len(cryptoSelection.ServerRandom), CryptoRandomSize)
	}
	return nil
}

func selectUDPPacketCodec(codecs []string) string {
	if Supports(codecs, UDPPacketCodecBinary) {
		return UDPPacketCodecBinary

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. On the client, include wire.UDPPacketCodecBinary in ClientHello.Capabilities.Message.UDPPacketCodecs when binary UDP encoding is acceptable.
  2. On the server, derive the selection with selectUDPPacketCodec(clientHello.Capabilities.Message.UDPPacketCodecs) instead of hardcoding it.
  3. In tests, generate the server hello from the same client hello object that is sent.

Example fix

// before (server)
selected.UDPPacketCodec = wire.UDPPacketCodecBinary // hardcoded

// after
selected.UDPPacketCodec = selectUDPPacketCodec(clientHello.Capabilities.Message.UDPPacketCodecs)
Defensive patterns

Strategy: validation

Validate before calling

// client side: advertise binary support if you can handle it
hello.Capabilities.Message.UDPPacketCodecs = append(
    hello.Capabilities.Message.UDPPacketCodecs, wire.UDPPacketCodecBinary)

// server side: only echo what the client offered
if !wire.Supports(clientHello.Capabilities.Message.UDPPacketCodecs, wire.UDPPacketCodecBinary) {
    selected.UDPPacketCodec = ""
}

Prevention

When it happens

Trigger: Client sends ClientHello with UDPPacketCodecs empty (or lacking "binary"), and the server responds with Selected.Message.UDPPacketCodec = "binary". Validation via Supports(clientHello.Capabilities.Message.UDPPacketCodecs, udpPacketCodec) fails.

Common situations: A server bug that ignores the client's advertised capabilities; a custom client that wants to opt out of the binary UDP codec but talks to a stock server that assumes support; mismatched test hello fixtures where the client hello and server hello are built independently.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/58e60b5ec63b6e42. Report an issue: GitHub.