{"record":{"id":"e5059c0a0a97a776","repo":"AlexxIT/go2rtc","slug":"wrong-topic-size","errorCode":null,"errorMessage":"wrong topic size","messagePattern":"wrong topic size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/mqtt/client.go","lineNumber":94,"sourceCode":"\n\tsize, err := ReadLen(c.conn)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tb0 := b[0]\n\tb = make([]byte, size)\n\tif _, err = io.ReadFull(c.conn, b); err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tif b0&0xF0 != PUBLISH {\n\t\treturn \"\", nil, nil\n\t}\n\n\ti := binary.BigEndian.Uint16(b)\n\tif uint32(i) > size {\n\t\treturn \"\", nil, errors.New(\"wrong topic size\")\n\t}\n\n\tb = b[2:]\n\n\tif qos := (b0 >> 1) & 0b11; qos == 0 {\n\t\treturn string(b[:i]), b[i:], nil\n\t}\n\n\t// response with packet ID\n\t_, _ = c.conn.Write([]byte{PUBACK, 2, b[i], b[i+1]})\n\n\treturn string(b[2:i]), b[i+2:], nil\n}\n\nfunc (c *Client) Close() error {\n\t// TODO: Teardown\n\treturn c.conn.Close()\n}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/mqtt/client.go#L76-L112","documentation":"During PUBLISH parsing, the MQTT client reads the 2-byte topic length prefix and rejects the packet if the declared topic length exceeds the size of the remaining buffer supplied to Read. This guards against truncated or maliciously crafted packets claiming a topic longer than the actual data. It means the caller passed a buffer that does not contain the full MQTT PUBLISH payload.","triggerScenarios":"Calling client.Read (pkg/mqtt/client.go Read) with a byte slice whose declared topic length (first 2 bytes after the fixed header) is greater than len(b)-2, e.g. a truncated PUBLISH packet or reading fewer bytes than the packet length.","commonSituations":"Reading from the socket with a short read / partial frame; feeding a packet captured before the full body arrived; a corrupted or non-MQTT stream being parsed as MQTT; off-by-one when trimming the fixed header before calling Read.","solutions":["Ensure the full MQTT packet (fixed header + remaining length + payload) is read into the buffer before calling Read; loop until the expected byte count is received.","Check that the fixed-header byte passed as b0 corresponds to the same buffer b you pass in; trim exactly the header bytes before Read.","Verify the peer/broker is speaking MQTT 3.1.x as expected and the stream is not corrupted or out of sync.","Log the declared topic length vs buffer size at the call site to identify short reads."],"exampleFix":"// before\nbuf := make([]byte, 64)\nn, _ := conn.Read(buf)\ntopic, payload, err := client.Read(buf[0], buf[:n])\n\n// after\n// read the full packet per remaining-length before parsing\nheader := make([]byte, 2)\nio.ReadFull(conn, header)\nremLen := int(header[1])\nbody := make([]byte, remLen)\nio.ReadFull(conn, body)\ntopic, payload, err := client.Read(header[0], body)","handlingStrategy":"validation","validationCode":"// before calling Read, ensure the buffer holds the declared payload\nif len(b) < 2 { return errors.New(\"buffer too short for topic length\") }\ndeclared := int(binary.BigEndian.Uint16(b))\nif declared > len(b)-2 { return errors.New(\"truncated MQTT publish packet\") }","typeGuard":null,"tryCatchPattern":"if topic, payload, err := c.Read(b0, b); err != nil {\n    if strings.Contains(err.Error(), \"wrong topic size\") {\n        // resync stream: drop this packet and re-read a full frame\n        return resyncStream(conn)\n    }\n    return err\n}","preventionTips":["Always read the complete MQTT frame (header + remaining length) before parsing.","Use io.ReadFull instead of a single conn.Read to avoid short reads.","Validate declared lengths against buffer sizes at protocol boundaries.","Log declared-vs-actual sizes when parsing fails to detect stream desync early."],"tags":["mqtt","protocol","buffer","packet-parsing"],"backgroundTag":"invalid-argument-value","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"}