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

  1. Build frames with EncodeV2MessageFrame so the type prefix is always written.
  2. When constructing manually, prepend the ID: binary.BigEndian.AppendUint16(nil, uint16(typeID)).
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/12ae3125691796d5. Report an issue: GitHub.