AlexxIT/go2rtc · error

tcp: buffer too small

Error message

tcp: buffer too small

What it means

Read reads a 2-byte big-endian length prefix followed by that many bytes into the caller-supplied buffer p. If len(p) is smaller than the announced frame size, the library refuses to read (leaving the frame unread) and returns "tcp: buffer too small". This is a caller contract error: the destination buffer must be at least as large as the incoming frame.

Solutions

  1. Pass a buffer at least as large as the maximum frame size (e.g. 1200 bytes, matching the internal loop buffer)
  2. Read the 2-byte length prefix first and grow the buffer to the announced size before the full read
  3. Check protocol/firmware version changes that increased maximum frame sizes
  4. Handle the returned error by draining/resetting the connection — the oversized frame is left in the stream and will corrupt subsequent reads if ignored

Example fix

// before
buf := make([]byte, 64)
n, err := conn.Read(buf)
// after
buf := make([]byte, 1200) // >= max cs2 frame size
n, err := conn.Read(buf)
Defensive patterns

Strategy: validation

Validate before calling

const maxFrame = 1200
func validateBuf(p []byte) error {
    if len(p) < maxFrame { return fmt.Errorf("buffer %d < max frame %d", len(p), maxFrame) }
    return nil
}
// call validateBuf(buf) before conn.Read(buf)

Type guard

func bufLargeEnough(p []byte) bool { return cap(p) >= 1200 }

Try / catch

if err := validateBuf(buf); err != nil { buf = make([]byte, 1200) }
n, err := conn.Read(buf)
if err != nil && strings.Contains(err.Error(), "buffer too small") {
    // stream desynced: reset the connection
    conn.Reset()
}

Prevention

When it happens

Trigger: Calling Read with a buffer shorter than the frame the peer sent — e.g. a fixed small scratch buffer receiving a larger frame, or a mis-sized buffer after a protocol/firmware change that increased maximum frame size.

Common situations: Hard-coded buffer sizes that assume a max frame which the firmware version exceeds; reusing a small tmp buffer for a new message type; off-by-N when accounting for the header vs payload size.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/2be1b10315146455. Report an issue: GitHub.

Appendix: source

Thrown at pkg/xiaomi/miss/cs2/conn.go:392

	if err != nil {
		return nil, err
	}
	return &tcpConn{conn.(*net.TCPConn), bufio.NewReader(conn)}, nil
}

type tcpConn struct {
	*net.TCPConn
	rd *bufio.Reader
}

func (c *tcpConn) Read(p []byte) (n int, err error) {
	tmp := make([]byte, 8)
	if _, err = io.ReadFull(c.rd, tmp); err != nil {
		return
	}
	n = int(binary.BigEndian.Uint16(tmp))
	if len(p) < n {
		return 0, fmt.Errorf("tcp: buffer too small")
	}
	_, err = io.ReadFull(c.rd, p[:n])
	//log.Printf("<- %x%x", tmp, p[:n])
	return
}

func (c *tcpConn) Write(req []byte) (n int, err error) {
	n = len(req)
	buf := make([]byte, 8+n)
	binary.BigEndian.PutUint16(buf, uint16(n))
	buf[2] = magicTCP
	copy(buf[8:], req)
	//log.Printf("-> %x", buf)
	_, err = c.TCPConn.Write(buf)
	return
}

func newDataChannel(pushSize, popSize int) *dataChannel {

View on GitHub (pinned to c245815e75)