AlexxIT/go2rtc · error

wrong start byte

Error message

wrong start byte

What it means

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.

Solutions

  1. Treat the connection as unrecoverable and reconnect: re-Dial and re-authenticate; the stream framing cannot be trusted.
  2. Check the network path (no TCP proxies/inspectors rewriting the stream).
  3. Verify the camera firmware hasn't changed the framing; update the driver if the protocol changed.
  4. Ensure no code path reads from c.r outside Read (extraneous reads desync the framing).
  5. Capture traffic on the port and confirm the packets start with the expected sync byte.

Example fix

// before: retrying Read on a desynced stream fails forever
for {
    cmd, b, err := client.Read() // keeps returning wrong start byte
}
// after: resync by reconnecting
if _, _, err := client.Read(); err != nil {
    client.Close()
    client, err = bubble.Dial(ctx, log, addr, user, pass)
}
Defensive patterns

Strategy: fallback

Try / catch

cmd, b, err := client.Read()
if err != nil && err.Error() == "wrong start byte" {
    client.Close()
    client, err = reconnectWithBackoff(ctx) // framing lost; full reconnect
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at pkg/bubble/client.go:184

	copy(b[10:], payload)

	_, err := c.conn.Write(b)
	return err
}

func (c *Client) Read() (byte, []byte, error) {
	if err := c.conn.SetReadDeadline(time.Now().Add(Timeout)); err != nil {
		return 0, nil, err
	}

	// 0xAA + size uint32 + cmd byte + ts uint32 + payload
	b := make([]byte, 10)
	if _, err := io.ReadFull(c.r, b); err != nil {
		return 0, nil, err
	}

	if b[0] != SyncByte {
		return 0, nil, errors.New("wrong start byte")
	}

	size := binary.BigEndian.Uint32(b[1:])
	payload := make([]byte, size-1-4)
	if _, err := io.ReadFull(c.r, payload); err != nil {
		return 0, nil, err
	}

	//timestamp := binary.BigEndian.Uint32(b[6:]) // in ms

	return b[5], payload, nil
}

func (c *Client) Play() error {
	// yeah, there's no mistake about the little endian
	b := make([]byte, 16)
	binary.LittleEndian.PutUint32(b, uint32(c.channel))
	binary.LittleEndian.PutUint32(b[4:], uint32(c.stream))

View on GitHub (pinned to c245815e75)