{"record":{"id":"4b487eb3f1cc9fc1","repo":"AlexxIT/go2rtc","slug":"read-error","errorCode":null,"errorMessage":"read error","messagePattern":"read error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/dvrip/client.go","lineNumber":161,"sourceCode":"\tif err = c.conn.SetWriteDeadline(time.Now().Add(time.Second * 5)); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn c.conn.Write(b)\n}\n\nfunc (c *Client) ReadChunk() (b []byte, err error) {\n\tif err = c.conn.SetReadDeadline(time.Now().Add(time.Second * 5)); err != nil {\n\t\treturn\n\t}\n\n\tb = make([]byte, 20)\n\tif _, err = io.ReadFull(c.rd, b); err != nil {\n\t\treturn\n\t}\n\n\tif b[0] != 255 {\n\t\treturn nil, errors.New(\"read error\")\n\t}\n\n\tc.session = binary.LittleEndian.Uint32(b[4:])\n\tsize := binary.LittleEndian.Uint32(b[16:])\n\n\tb = make([]byte, size)\n\tif _, err = io.ReadFull(c.rd, b); err != nil {\n\t\treturn\n\t}\n\n\treturn\n}\n\nfunc (c *Client) ReadPacket() (pType byte, payload []byte, err error) {\n\tvar b []byte\n\n\t// many cameras may split packet to multiple chunks\n\t// some rare cameras may put multiple packets to single chunk","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/dvrip/client.go#L143-L179","documentation":"dvrip.Client.ReadChunk (pkg/dvrip/client.go:161) reads the DVRIP binary chunk framing: a 20-byte header whose first byte must be 0xFF. If b[0] != 255 the stream is not a valid DVRIP chunk and the client returns \"read error\". Like other start-byte checks, it means the TCP stream is misaligned or is not speaking DVRIP at all.","triggerScenarios":"ReadChunk, invoked by ReadPacket and ReadJSON, when the first header byte is not 0xFF — e.g. garbage after a session drop, an HTTP error page, or a device answering with a different protocol on that port.","commonSituations":"Connecting to the wrong port (web UI port vs DVRIP port 34567); camera/firmware closing or corrupting the connection mid-read; firewall/NAT injecting data; stale session where the device reset the stream.","solutions":["Reconnect: close the client and Dial again; the stream framing is unrecoverable once desynced.","Verify the target port speaks DVRIP (typically 34567) and not the camera's HTTP interface.","Check device model/firmware compatibility with this DVRIP driver.","Inspect raw traffic with tcpdump/wireshark to see what bytes actually arrive at that offset.","Rule out middleboxes (transparent proxies, DPI) altering the TCP payload."],"exampleFix":"// before: retrying reads on a desynced connection\npkt, err := client.ReadPacket() // read error every time\n// after\nif err != nil {\n    client.Close()\n    client, err = dvrip.Dial(ctx, host, user, pass) // fresh session\n}","handlingStrategy":"fallback","validationCode":"// sanity-check the port speaks DVRIP before Dial\nconn, err := net.DialTimeout(\"tcp\", host+\":34567\", time.Second)\nif err != nil { return err }\nconn.Close()","typeGuard":null,"tryCatchPattern":"pkt, err := client.ReadPacket()\nif err != nil && err.Error() == \"read error\" {\n    client.Close()\n    client, err = dvripReconnect(ctx) // desynced stream; reconnect\n}","preventionTips":["Connect to the DVRIP port (usually 34567), not the HTTP UI port","Recreate the client on any protocol error; don't retry reads","Verify device model/firmware compatibility","Monitor TCP resets and re-Dial proactively"],"tags":["network","protocol","stream","dvr"],"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"}