fatedier/frp · error

UDP packet codec %q requires wire protocol v2

Error message

UDP packet codec %q requires wire protocol v2

What it means

RegisterControl validates transport options at login: with wire protocol v1, a non-empty udpPacketCodec is rejected because UDP packet codecs only exist in the v2 protocol. The client asked for a codec feature its declared protocol cannot carry, so the control connection is refused.

Source

Thrown at server/service.go:777

					return
				}
				go svr.handleConnection(ctx, netpkg.QuicStreamToNetConn(stream, frpConn), false)
			}
		}(context.Background(), c)
	}
}

func (svr *Service) RegisterControl(
	ctlConn *msg.Conn,
	loginMsg *msg.Login,
	internal bool,
	wireProtocol string,
	udpPacketCodec string,
) (*Control, error) {
	switch wireProtocol {
	case wire.ProtocolV1:
		if udpPacketCodec != "" {
			return nil, fmt.Errorf("UDP packet codec %q requires wire protocol v2", udpPacketCodec)
		}
	case wire.ProtocolV2:
		if udpPacketCodec != "" && udpPacketCodec != wire.UDPPacketCodecBinary {
			return nil, fmt.Errorf("unsupported UDP packet codec selection: %s", udpPacketCodec)
		}
	default:
		return nil, fmt.Errorf("unsupported wire protocol: %s", wireProtocol)
	}
	// If client's RunID is empty, it's a new client, we just create a new controller.
	// Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one.
	var err error
	if loginMsg.RunID == "" {
		loginMsg.RunID, err = util.RandID()
		if err != nil {
			return nil, err
		}
	}
	if err := validation.ValidateRunID(loginMsg.RunID); err != nil {

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Set the client transport protocol to v2 (transport.protocol) so the codec is honored
  2. Or remove/comment out the udpPacketCodec setting to stay on v1
  3. Confirm frps also supports v2 before switching protocols

Example fix

# before
[transport]
protocol = "v1"
udpPacketCodec = "binary"

# after
[transport]
protocol = "v2"
udpPacketCodec = "binary"
Defensive patterns

Strategy: validation

Validate before calling

// Validate client transport config before connecting.
if cfg.UDPPacketCodec != "" && cfg.Protocol != "v2" {
    return fmt.Errorf("udpPacketCodec requires transport.protocol = v2")
}

Prevention

When it happens

Trigger: Client config sets a udpPacketCodec option while transport protocol is unset/v1; enabling a codec knob copied from a v2 example onto a v1 client; tooling that writes the codec field unconditionally.

Common situations: Adopting the new UDP codec feature on an older client config that still defaults to protocol v1; partial config migration.

Related errors


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