fatedier/frp · error
message frame payload too short
Error message
message frame payload too short
What it means
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.
Source
Thrown at pkg/msg/wire_v2.go:128
return err
}
return DecodeV2MessageFrameInto(f, m)
}
func (rw *V2ReadWriter) WriteMsg(m Message) error {
f, err := EncodeV2MessageFrame(m)
if err != nil {
return err
}
return rw.conn.WriteFrame(f)
}
func DecodeV2MessageFrame(f *wire.Frame) (Message, error) {
if f.Type != wire.FrameTypeMessage {
return nil, fmt.Errorf("unexpected frame type %d, want %d", f.Type, wire.FrameTypeMessage)
}
if len(f.Payload) < 2 {
return nil, fmt.Errorf("message frame payload too short")
}
typeID := binary.BigEndian.Uint16(f.Payload[:2])
t, ok := v2MsgReflectTypeMap[typeID]
if !ok {
return nil, fmt.Errorf("unknown v2 message type %d", typeID)
}
m := reflect.New(t).Interface()
if err := json.Unmarshal(f.Payload[2:], m); err != nil {
return nil, err
}
return m, nil
}
func DecodeV2MessageFrameInto(f *wire.Frame, out Message) error {
if f.Type != wire.FrameTypeMessage {
return fmt.Errorf("unexpected frame type %d, want %d", f.Type, wire.FrameTypeMessage)
}
if len(f.Payload) < 2 {View on GitHub (pinned to 6c8a8d0a97)
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.
Example fix
// before
f := &wire.Frame{Type: wire.FrameTypeMessage, Payload: []byte(`{}`)}
// after
f, err := msg.EncodeV2MessageFrame(&msg.Ping{}) Defensive patterns
Strategy: validation
Validate before calling
if f.Type != wire.FrameTypeMessage || len(f.Payload) < 2 {
return errors.New("malformed v2 message frame")
} Prevention
- Use EncodeV2MessageFrame for all frame construction.
- Fuzz your encoders against the decoders to catch length bugs early.
When it happens
Trigger: 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.
Common situations: Unit tests constructing frames manually; fuzzing corpora; a peer interrupted mid-write producing a short final frame.
Related errors
- message frame payload too short
- unexpected frame type %d, want %d
- unexpected frame type %d, want %d
- unsupported wire protocol %q
- invalid pool count %d, must be non-negative
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/12ae3125691796d5.
Report an issue: GitHub.