{"record":{"id":"2f4171e42261727b","repo":"fatedier/frp","slug":"message-frame-payload-too-short","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/udp_binary.go","lineNumber":291,"sourceCode":"\t\t}\n\t\treturn rw.conn.WriteFrame(frame)\n\t}\n\tbody, err := EncodeUDPPacketBinary(packet)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpayload := make([]byte, 2+len(body))\n\tbinary.BigEndian.PutUint16(payload[:2], V2TypeUDPPacketBinary)\n\tcopy(payload[2:], body)\n\treturn rw.conn.WriteFrame(&wire.Frame{Type: wire.FrameTypeMessage, Payload: payload})\n}\n\nfunc decodeV2BinaryUDPPacketFrame(frame *wire.Frame) (*UDPPacket, error) {\n\tif frame.Type != wire.FrameTypeMessage {\n\t\treturn nil, fmt.Errorf(\"unexpected frame type %d, want %d\", frame.Type, wire.FrameTypeMessage)\n\t}\n\tif len(frame.Payload) < 2 {\n\t\treturn nil, fmt.Errorf(\"message frame payload too short\")\n\t}\n\tif binary.BigEndian.Uint16(frame.Payload[:2]) != V2TypeUDPPacketBinary {\n\t\treturn nil, unexpectedV2UDPPacketType(frame)\n\t}\n\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}","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/msg/udp_binary.go#L273-L309","documentation":"decodeV2BinaryUDPPacketFrame requires at least 2 payload bytes (the big-endian message type ID) before it can dispatch. A frame with a 0- or 1-byte payload cannot carry a type ID, so it is rejected. Like other framing checks here, it indicates malformed input rather than a recoverable condition.","triggerScenarios":"A FrameTypeMessage frame with payload shorter than 2 bytes reaches decodeV2BinaryUDPPacketFrame — crafted input, stream desynchronization, or a bug in a custom frame producer.","commonSituations":"Fuzzing the decoder with empty payloads; a truncated write on the peer side; unit-test fixtures built with an empty payload.","solutions":["When constructing frames in tests or custom code, always prepend the 2-byte type ID to the payload.","Prefer EncodeV2MessageFrame / the library's WriteMsg instead of hand-building frames.","Treat receipt at runtime as a fatal connection error."],"exampleFix":"// before (test builds frame without type prefix)\nframe := &wire.Frame{Type: wire.FrameTypeMessage, Payload: []byte{0x01}}\n\n// after\npayload := binary.BigEndian.AppendUint16(nil, uint16(msg.V2TypeUDPPacketBinary))\nframe := &wire.Frame{Type: wire.FrameTypeMessage, Payload: payload}","handlingStrategy":"validation","validationCode":"func validMessageFrame(f *wire.Frame) bool {\n\treturn f.Type == wire.FrameTypeMessage && len(f.Payload) >= 2\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the 2-byte type ID when building frames; use EncodeV2MessageFrame.","Validate frame shape in test helpers before feeding the decoder."],"tags":["protocol","framing","validation","udp","frp"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}