{"record":{"id":"12ae3125691796d5","repo":"fatedier/frp","slug":"message-frame-payload-too-short-12ae31","errorCode":null,"errorMessage":"message frame payload too short","messagePattern":"message frame payload too short","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/msg/wire_v2.go","lineNumber":128,"sourceCode":"\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 {\n\t\treturn fmt.Errorf(\"unexpected frame type %d, want %d\", f.Type, wire.FrameTypeMessage)\n\t}\n\tif len(f.Payload) < 2 {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/msg/wire_v2.go#L110-L146","documentation":"DecodeV2MessageFrame rejects a message frame whose payload is shorter than the mandatory 2-byte big-endian type ID. Every v2 message frame is at least 2 bytes; anything shorter is malformed. The same guard exists in DecodeV2MessageFrameInto and the UDP binary decoder, because the type ID is the dispatch key for the whole v2 message layer.","triggerScenarios":"DecodeV2MessageFrame(&wire.Frame{Type: FrameTypeMessage, Payload: []byte{}}) — empty or 1-byte payloads from fuzzing, truncated writes, or hand-built test frames that forgot the type prefix.","commonSituations":"Unit tests constructing frames manually; fuzzing corpora; a peer interrupted mid-write producing a short final frame.","solutions":["Build frames with EncodeV2MessageFrame so the type prefix is always written.","When constructing manually, prepend the ID: binary.BigEndian.AppendUint16(nil, uint16(typeID)).","Reject short frames before decoding in custom pipelines."],"exampleFix":"// before\nf := &wire.Frame{Type: wire.FrameTypeMessage, Payload: []byte(`{}`)}\n\n// after\nf, err := msg.EncodeV2MessageFrame(&msg.Ping{})","handlingStrategy":"validation","validationCode":"if f.Type != wire.FrameTypeMessage || len(f.Payload) < 2 {\n\treturn errors.New(\"malformed v2 message frame\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use EncodeV2MessageFrame for all frame construction.","Fuzz your encoders against the decoders to catch length bugs early."],"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"}