{"record":{"id":"00d6dc1c388733f8","repo":"fatedier/frp","slug":"unexpected-message-type-d-want-d","errorCode":null,"errorMessage":"unexpected message type %d, want %d","messagePattern":"unexpected message type (.+?), want (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/msg/udp_binary.go","lineNumber":314,"sourceCode":"\treturn DecodeUDPPacketBinary(frame.Payload[2:])\n}\n\nfunc isV2MessageType(frame *wire.Frame, typeID uint16) bool {\n\treturn frame.Type == wire.FrameTypeMessage && len(frame.Payload) >= 2 && binary.BigEndian.Uint16(frame.Payload[:2]) == typeID\n}\n\nfunc unexpectedV2UDPPacketType(frame *wire.Frame) error {\n\tif frame.Type != wire.FrameTypeMessage {\n\t\treturn fmt.Errorf(\"unexpected frame type %d, want %d\", frame.Type, wire.FrameTypeMessage)\n\t}\n\tif len(frame.Payload) < 2 {\n\t\treturn fmt.Errorf(\"message frame payload too short\")\n\t}\n\ttypeID := binary.BigEndian.Uint16(frame.Payload[:2])\n\tif typeID == V2TypeUDPPacket {\n\t\treturn fmt.Errorf(\"received JSON UDP packet after binary codec negotiation\")\n\t}\n\treturn fmt.Errorf(\"unexpected message type %d, want %d\", typeID, V2TypeUDPPacketBinary)\n}\n\n// NewUDPPacketReadWriter selects the negotiated packet codec without changing\n// the framing or codecs used by non-UDP messages on the work connection.\nfunc NewUDPPacketReadWriter(rw io.ReadWriter, wireProtocol, udpPacketCodec string) (ReadWriter, error) {\n\tswitch wireProtocol {\n\tcase \"\", wire.ProtocolV1:\n\t\tif udpPacketCodec != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"UDP packet codec %q requires wire protocol v2\", udpPacketCodec)\n\t\t}\n\t\treturn NewV1ReadWriter(rw), nil\n\tcase wire.ProtocolV2:\n\t\tswitch udpPacketCodec {\n\t\tcase \"\":\n\t\t\treturn NewV2ReadWriter(rw), nil\n\t\tcase wire.UDPPacketCodecBinary:\n\t\t\treturn NewV2BinaryUDPPacketReadWriter(rw), nil\n\t\tdefault:","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/msg/udp_binary.go#L296-L332","documentation":"unexpectedV2UDPPacketType's final branch: the frame is a well-formed message frame carrying a known-shape but unexpected message type ID — not 13 (JSON UDP) and not 19 (binary UDP). E.g. a Login or Ping message routed to the binary UDP packet decoder. This means control-plane traffic is arriving on a path dedicated to UDP packets, usually a misuse of the read writer or a desynchronized stream.","triggerScenarios":"ReadMsgInto(&msg.UDPPacket{}) receives any non-UDP v2 message (Login=1, Ping=11, NatHoleVisitor=14, etc.) — e.g. pointing V2BinaryUDPPacketReadWriter at a control connection, or a stream that slipped alignment.","commonSituations":"Custom code reuses one ReadWriter for both control messages and UDP packets; framing desync causes a control frame to be read where a UDP packet was expected.","solutions":["Give work-conn UDP traffic its own ReadWriter; use NewUDPPacketReadWriter rather than wiring the binary reader by hand.","Do not share a single wire.Conn between the control loop and UDP forwarding.","On this error, close the connection — the message stream ordering is broken."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := rw.ReadMsgInto(&msg.UDPPacket{}); err != nil {\n\tif strings.Contains(err.Error(), \"unexpected message type\") {\n\t\t// wrong message arrived on the UDP path: close and reconnect\n\t\tconn.Close()\n\t}\n}","preventionTips":["Dedicate one ReadWriter per traffic class (control vs UDP).","Construct readers via NewUDPPacketReadWriter."],"tags":["protocol","udp","message-routing","frp"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}