fatedier/frp · error
message frame payload too short
Error message
message frame payload too short
What it means
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.
Source
Thrown at pkg/msg/udp_binary.go:291
}
return rw.conn.WriteFrame(frame)
}
body, err := EncodeUDPPacketBinary(packet)
if err != nil {
return err
}
payload := make([]byte, 2+len(body))
binary.BigEndian.PutUint16(payload[:2], V2TypeUDPPacketBinary)
copy(payload[2:], body)
return rw.conn.WriteFrame(&wire.Frame{Type: wire.FrameTypeMessage, Payload: payload})
}
func decodeV2BinaryUDPPacketFrame(frame *wire.Frame) (*UDPPacket, error) {
if frame.Type != wire.FrameTypeMessage {
return nil, fmt.Errorf("unexpected frame type %d, want %d", frame.Type, wire.FrameTypeMessage)
}
if len(frame.Payload) < 2 {
return nil, fmt.Errorf("message frame payload too short")
}
if binary.BigEndian.Uint16(frame.Payload[:2]) != V2TypeUDPPacketBinary {
return nil, unexpectedV2UDPPacketType(frame)
}
return DecodeUDPPacketBinary(frame.Payload[2:])
}
func isV2MessageType(frame *wire.Frame, typeID uint16) bool {
return frame.Type == wire.FrameTypeMessage && len(frame.Payload) >= 2 && binary.BigEndian.Uint16(frame.Payload[:2]) == typeID
}
func unexpectedV2UDPPacketType(frame *wire.Frame) error {
if frame.Type != wire.FrameTypeMessage {
return fmt.Errorf("unexpected frame type %d, want %d", frame.Type, wire.FrameTypeMessage)
}
if len(frame.Payload) < 2 {
return fmt.Errorf("message frame payload too short")
}View on GitHub (pinned to 6c8a8d0a97)
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.
Example fix
// before (test builds frame without type prefix)
frame := &wire.Frame{Type: wire.FrameTypeMessage, Payload: []byte{0x01}}
// after
payload := binary.BigEndian.AppendUint16(nil, uint16(msg.V2TypeUDPPacketBinary))
frame := &wire.Frame{Type: wire.FrameTypeMessage, Payload: payload} Defensive patterns
Strategy: validation
Validate before calling
func validMessageFrame(f *wire.Frame) bool {
return f.Type == wire.FrameTypeMessage && len(f.Payload) >= 2
} Prevention
- Always include the 2-byte type ID when building frames; use EncodeV2MessageFrame.
- Validate frame shape in test helpers before feeding the decoder.
When it happens
Trigger: A FrameTypeMessage frame with payload shorter than 2 bytes reaches decodeV2BinaryUDPPacketFrame — crafted input, stream desynchronization, or a bug in a custom frame producer.
Common situations: Fuzzing the decoder with empty payloads; a truncated write on the peer side; unit-test fixtures built with an empty payload.
Related errors
- unexpected frame type %d, want %d
- unexpected frame type %d, want %d
- message frame payload too short
- truncated zone
- IPv4 zone is forbidden
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/2f4171e42261727b.
Report an issue: GitHub.