{"record":{"id":"5206671587e83a1c","repo":"AlexxIT/go2rtc","slug":"wrong-start-byte","errorCode":null,"errorMessage":"wrong start byte","messagePattern":"wrong start byte","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/bubble/client.go","lineNumber":184,"sourceCode":"\tcopy(b[10:], payload)\n\n\t_, err := c.conn.Write(b)\n\treturn err\n}\n\nfunc (c *Client) Read() (byte, []byte, error) {\n\tif err := c.conn.SetReadDeadline(time.Now().Add(Timeout)); err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\t// 0xAA + size uint32 + cmd byte + ts uint32 + payload\n\tb := make([]byte, 10)\n\tif _, err := io.ReadFull(c.r, b); err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\tif b[0] != SyncByte {\n\t\treturn 0, nil, errors.New(\"wrong start byte\")\n\t}\n\n\tsize := binary.BigEndian.Uint32(b[1:])\n\tpayload := make([]byte, size-1-4)\n\tif _, err := io.ReadFull(c.r, payload); err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\t//timestamp := binary.BigEndian.Uint32(b[6:]) // in ms\n\n\treturn b[5], payload, nil\n}\n\nfunc (c *Client) Play() error {\n\t// yeah, there's no mistake about the little endian\n\tb := make([]byte, 16)\n\tbinary.LittleEndian.PutUint32(b, uint32(c.channel))\n\tbinary.LittleEndian.PutUint32(b[4:], uint32(c.stream))","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/bubble/client.go#L166-L202","documentation":"bubble.Client.Read (pkg/bubble/client.go:184) parses the wire framing of the Bubble protocol: it reads a 10-byte header via io.ReadFull and requires the first byte to be SyncByte. If the stream is misaligned or carries foreign data, b[0] != SyncByte and the client returns \"wrong start byte\". This is a stream-synchronization failure: the reader is no longer at a packet boundary.","triggerScenarios":"Calling Read (directly or via Dial, Handle, ReadResponseHeader) when the first byte of the next 10-byte header is not SyncByte — misaligned stream, partial/garbage data from the camera, or reading from the wrong offset.","commonSituations":"Camera dropped/corrupted TCP stream mid-session and bytes shifted; a proxy or middlebox altering the payload; reading a non-Bubble stream from that port; a bug leaving a partial packet read so the next Read starts mid-payload.","solutions":["Treat the connection as unrecoverable and reconnect: re-Dial and re-authenticate; the stream framing cannot be trusted.","Check the network path (no TCP proxies/inspectors rewriting the stream).","Verify the camera firmware hasn't changed the framing; update the driver if the protocol changed.","Ensure no code path reads from c.r outside Read (extraneous reads desync the framing).","Capture traffic on the port and confirm the packets start with the expected sync byte."],"exampleFix":"// before: retrying Read on a desynced stream fails forever\nfor {\n    cmd, b, err := client.Read() // keeps returning wrong start byte\n}\n// after: resync by reconnecting\nif _, _, err := client.Read(); err != nil {\n    client.Close()\n    client, err = bubble.Dial(ctx, log, addr, user, pass)\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"cmd, b, err := client.Read()\nif err != nil && err.Error() == \"wrong start byte\" {\n    client.Close()\n    client, err = reconnectWithBackoff(ctx) // framing lost; full reconnect\n}","preventionTips":["Never read from the connection outside the library's Read","Reconnect on any framing error instead of retrying reads","Keep the TCP path free of rewriting middleboxes","Watch for camera resets and re-Dial proactively"],"tags":["network","protocol","stream","camera"],"backgroundTag":"unexpected-api-response-shape","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"}