{"record":{"id":"ac1b61246df6651a","repo":"fatedier/frp","slug":"unexpected-frame-type-d-want-d-ac1b61","errorCode":null,"errorMessage":"unexpected frame type %d, want %d","messagePattern":"unexpected frame type (.+?), want (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/msg/wire_v2.go","lineNumber":125,"sourceCode":"func (rw *V2ReadWriter) ReadMsgInto(m Message) error {\n\tf, err := rw.conn.ReadFrame()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn DecodeV2MessageFrameInto(f, m)\n}\n\nfunc (rw *V2ReadWriter) WriteMsg(m Message) error {\n\tf, err := EncodeV2MessageFrame(m)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn rw.conn.WriteFrame(f)\n}\n\nfunc DecodeV2MessageFrame(f *wire.Frame) (Message, error) {\n\tif f.Type != wire.FrameTypeMessage {\n\t\treturn nil, fmt.Errorf(\"unexpected frame type %d, want %d\", f.Type, wire.FrameTypeMessage)\n\t}\n\tif len(f.Payload) < 2 {\n\t\treturn nil, fmt.Errorf(\"message frame payload too short\")\n\t}\n\ttypeID := binary.BigEndian.Uint16(f.Payload[:2])\n\tt, ok := v2MsgReflectTypeMap[typeID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unknown v2 message type %d\", typeID)\n\t}\n\tm := reflect.New(t).Interface()\n\tif err := json.Unmarshal(f.Payload[2:], m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc DecodeV2MessageFrameInto(f *wire.Frame, out Message) error {\n\tif f.Type != wire.FrameTypeMessage {","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/msg/wire_v2.go#L107-L143","documentation":"DecodeV2MessageFrame (and DecodeV2MessageFrameInto) requires the frame to be a FrameTypeMessage frame; v2 messages are JSON bodies prefixed with a 2-byte type ID and carried exclusively in message frames. A frame of any other wire type (stream/keepalive/etc.) reaching this decoder means the caller is using the v2 message decoder on a non-message frame — a framing-layer misuse or stream corruption.","triggerScenarios":"Passing a non-message wire.Frame to DecodeV2MessageFrame directly, or ReadMsg() on a V2ReadWriter whose underlying wire.Conn delivered a non-message frame — usually a mis-wired connection or fuzzed input.","commonSituations":"Custom code decodes raw frames manually and hands the wrong frame type; stream desync after an earlier error; replay harnesses feeding arbitrary frames.","solutions":["Filter by frame.Type == wire.FrameTypeMessage before calling DecodeV2MessageFrame.","Prefer the ReadWriter's ReadMsg, which only ever handles the appropriate frames per negotiated protocol.","Treat unexpected frame types at runtime as fatal for the connection."],"exampleFix":"// before\nm, err := msg.DecodeV2MessageFrame(frame) // frame may be a stream frame\n\n// after\nif frame.Type != wire.FrameTypeMessage {\n\treturn fmt.Errorf(\"not a message frame: %d\", frame.Type)\n}\nm, err := msg.DecodeV2MessageFrame(frame)","handlingStrategy":"validation","validationCode":"if frame.Type != wire.FrameTypeMessage {\n\treturn fmt.Errorf(\"skipping non-message frame type %d\", frame.Type)\n}","typeGuard":null,"tryCatchPattern":"m, err := msg.DecodeV2MessageFrame(f)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"unexpected frame type\") {\n\t\t// framing misuse or corruption: drop the connection\n\t\tconn.Close()\n\t\treturn err\n\t}\n}","preventionTips":["Filter frames by type before decoding in custom pipelines.","Prefer ReadMsg over manual frame decoding."],"tags":["protocol","framing","validation","frp"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}