fatedier/frp · error
unknown v2 message type %d
Error message
unknown v2 message type %d
What it means
DecodeV2MessageFrame looked up the 2-byte type ID in v2MsgReflectTypeMap (built from the 18 registered message types, IDs 1-18 plus 19 for binary UDP) and found no entry. The peer sent a type ID this build does not know — either a message kind introduced in a newer frp version, a removed legacy ID, or garbage bytes. Because the JSON body layout is type-specific, decoding cannot proceed.
Source
Thrown at pkg/msg/wire_v2.go:133
func (rw *V2ReadWriter) WriteMsg(m Message) error {
f, err := EncodeV2MessageFrame(m)
if err != nil {
return err
}
return rw.conn.WriteFrame(f)
}
func DecodeV2MessageFrame(f *wire.Frame) (Message, error) {
if f.Type != wire.FrameTypeMessage {
return nil, fmt.Errorf("unexpected frame type %d, want %d", f.Type, wire.FrameTypeMessage)
}
if len(f.Payload) < 2 {
return nil, fmt.Errorf("message frame payload too short")
}
typeID := binary.BigEndian.Uint16(f.Payload[:2])
t, ok := v2MsgReflectTypeMap[typeID]
if !ok {
return nil, fmt.Errorf("unknown v2 message type %d", typeID)
}
m := reflect.New(t).Interface()
if err := json.Unmarshal(f.Payload[2:], m); err != nil {
return nil, err
}
return m, nil
}
func DecodeV2MessageFrameInto(f *wire.Frame, out Message) error {
if f.Type != wire.FrameTypeMessage {
return fmt.Errorf("unexpected frame type %d, want %d", f.Type, wire.FrameTypeMessage)
}
if len(f.Payload) < 2 {
return fmt.Errorf("message frame payload too short")
}
typeID := binary.BigEndian.Uint16(f.Payload[:2])
outType := reflect.TypeOf(out)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Upgrade both frpc and frps to the same frp release.
- If you fork the protocol, allocate new type IDs consistently on both sides and rebuild both binaries.
- Treat the error as fatal for the connection — the following JSON body cannot be interpreted.
- Verify you are connecting to an actual frp v2 endpoint, not some other service on that port.
Defensive patterns
Strategy: try-catch
Try / catch
m, err := msg.DecodeV2MessageFrame(f)
if err != nil {
if strings.Contains(err.Error(), "unknown v2 message type") {
// peer speaks a newer/older protocol: version skew — upgrade both sides, then reconnect
conn.Close()
return err
}
} Prevention
- Run the same frp release on frpc and frps; pin versions in deployment tooling.
- If forking the protocol, keep a shared type-ID registry and version handshake.
- Treat unknown-type errors as fatal; the body layout is unknowable.
When it happens
Trigger: A newer frps sends a message type not present in the older frpc's registry (forward-compat gap); a peer from a different protocol entirely; fuzzed type IDs; desynchronized stream landing on this decoder.
Common situations: Version skew between frpc and frps after upgrading only one side; custom forks that add message types without coordinating IDs; connecting a non-frp service to an frp port.
Related errors
- received JSON UDP packet after binary codec negotiation
- UDP packet codec %q requires wire protocol v2
- unexpected frame type %d, want %d
- invalid transport.protocol, optional values are %v
- %s cannot be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/4756ffbb7e88f135.
Report an issue: GitHub.