{"record":{"id":"2be1b10315146455","repo":"AlexxIT/go2rtc","slug":"tcp-buffer-too-small","errorCode":null,"errorMessage":"tcp: buffer too small","messagePattern":"tcp: buffer too small","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/xiaomi/miss/cs2/conn.go","lineNumber":392,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &tcpConn{conn.(*net.TCPConn), bufio.NewReader(conn)}, nil\n}\n\ntype tcpConn struct {\n\t*net.TCPConn\n\trd *bufio.Reader\n}\n\nfunc (c *tcpConn) Read(p []byte) (n int, err error) {\n\ttmp := make([]byte, 8)\n\tif _, err = io.ReadFull(c.rd, tmp); err != nil {\n\t\treturn\n\t}\n\tn = int(binary.BigEndian.Uint16(tmp))\n\tif len(p) < n {\n\t\treturn 0, fmt.Errorf(\"tcp: buffer too small\")\n\t}\n\t_, err = io.ReadFull(c.rd, p[:n])\n\t//log.Printf(\"<- %x%x\", tmp, p[:n])\n\treturn\n}\n\nfunc (c *tcpConn) Write(req []byte) (n int, err error) {\n\tn = len(req)\n\tbuf := make([]byte, 8+n)\n\tbinary.BigEndian.PutUint16(buf, uint16(n))\n\tbuf[2] = magicTCP\n\tcopy(buf[8:], req)\n\t//log.Printf(\"-> %x\", buf)\n\t_, err = c.TCPConn.Write(buf)\n\treturn\n}\n\nfunc newDataChannel(pushSize, popSize int) *dataChannel {","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/xiaomi/miss/cs2/conn.go#L374-L410","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a buffer at least as large as the maximum frame size (e.g. 1200 bytes, matching the internal loop buffer)","Read the 2-byte length prefix first and grow the buffer to the announced size before the full read","Check protocol/firmware version changes that increased maximum frame sizes","Handle the returned error by draining/resetting the connection — the oversized frame is left in the stream and will corrupt subsequent reads if ignored"],"exampleFix":"// before\nbuf := make([]byte, 64)\nn, err := conn.Read(buf)\n// after\nbuf := make([]byte, 1200) // >= max cs2 frame size\nn, err := conn.Read(buf)","handlingStrategy":"validation","validationCode":"const maxFrame = 1200\nfunc validateBuf(p []byte) error {\n    if len(p) < maxFrame { return fmt.Errorf(\"buffer %d < max frame %d\", len(p), maxFrame) }\n    return nil\n}\n// call validateBuf(buf) before conn.Read(buf)","typeGuard":"func bufLargeEnough(p []byte) bool { return cap(p) >= 1200 }","tryCatchPattern":"if err := validateBuf(buf); err != nil { buf = make([]byte, 1200) }\nn, err := conn.Read(buf)\nif err != nil && strings.Contains(err.Error(), \"buffer too small\") {\n    // stream desynced: reset the connection\n    conn.Reset()\n}","preventionTips":["Always allocate buffers at the protocol's maximum frame size","Account for header vs payload size when sizing buffers","Re-check buffer sizes after any firmware/protocol upgrade","Treat this error as fatal for the stream and reset the connection"],"tags":["tcp","buffer","framing","xiaomi-cs2"],"backgroundTag":"buffer-too-small","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}