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
- Set the client transport protocol to v2 (transport.protocol) so the codec is honored
- Or remove/comment out the udpPacketCodec setting to stay on v1
- 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
- Config-schema lint: udpPacketCodec is only legal together with protocol v2
- Default new deployments to matching protocol settings on both ends
- Fail fast at config load rather than at server login
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
- unsupported UDP packet codec selection: %s
- localAddr is required
- localPath is required
- unixPath is required
- name should not be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/a822eda2372c62a9.
Report an issue: GitHub.