{"record":{"id":"bff3ca8f82442394","repo":"AlexxIT/go2rtc","slug":"mpegts-wrong-sync-byte","errorCode":null,"errorMessage":"mpegts: wrong sync byte","messagePattern":"mpegts: wrong sync byte","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/mpegts/demuxer.go","lineNumber":74,"sourceCode":"\t\t\t\t\tpkt.Payload = append(pkt.Payload, pes.StreamType)\n\t\t\t\t}\n\t\t\t\treturn pkt, nil\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif pkt := d.readPES(pid, start); pkt != nil {\n\t\t\treturn pkt, nil\n\t\t}\n\t}\n}\n\nfunc (d *Demuxer) readPacketHeader() (pid uint16, start bool, err error) {\n\td.reset()\n\n\tsb := d.readByte() // Sync byte\n\tif sb != SyncByte {\n\t\treturn 0, false, errors.New(\"mpegts: wrong sync byte\")\n\t}\n\n\t_ = d.readBit()        // Transport error indicator (TEI)\n\tpusi := d.readBit()    // Payload unit start indicator (PUSI)\n\t_ = d.readBit()        // Transport priority\n\tpid = d.readBits16(13) // PID\n\n\t_ = d.readBits(2) // Transport scrambling control (TSC)\n\taf := d.readBit() // Adaptation field\n\t_ = d.readBit()   // Payload\n\t_ = d.readBits(4) // Continuity counter\n\n\tif af != 0 {\n\t\tadSize := d.readByte() // Adaptation field length\n\t\tif adSize > PacketSize-6 {\n\t\t\treturn 0, false, errors.New(\"mpegts: wrong adaptation size\")\n\t\t}\n\t\td.skip(adSize)","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/mpegts/demuxer.go#L56-L92","documentation":"MPEG-TS packets must start with the fixed sync byte 0x47. Demuxer.readPacketHeader reads the first byte of each 188-byte packet and returns this error immediately if it differs, meaning the byte stream is no longer packet-aligned or is not an MPEG-TS stream at all.","triggerScenarios":"Calling ReadPacket on data that is not MPEG-TS (e.g. an MP4, PS, or FLV stream), on a stream with lost bytes mid-way (partial reads, HTTP response truncated), on a TS stream with a non-standard packet size where alignment drifts, or starting to read at a non-zero offset into the stream.","commonSituations":"HTTP live streams where the first response bytes are HTTP headers/garbage; recording pipelines reading from a resync-prone pipe; camera TS streams with dropped UDP packets causing desync; accidentally demuxing raw H.264 or an MPEG-Program-Stream; reading a file from a wrong offset after a seek.","solutions":["Verify the input actually is MPEG-TS: first byte should be 0x47 and packets recur every 188 bytes — check with `xxd file | head`.","Restart reading from a stream boundary (start of file, start of HTTP response) so the demuxer begins on a packet boundary.","Resynchronize the stream by scanning forward for the next 0x47 byte and re-aligning (or wrap the reader to skip until 0x47) before calling ReadPacket again.","For unreliable transports (UDP/pipe), add loss handling upstream or use a depacketizer/resync wrapper, since a single lost byte desyncs all subsequent packets."],"exampleFix":"// before: reading from an offset mid-packet\nf.Seek(137, 0)\npid, start, err := demuxer.ReadPacket() // wrong sync byte\n\n// after: re-align to the next 0x47 sync byte\nf.Seek(137, 0)\nb, _ := f.Peek(1)\nif b[0] != 0x47 {\n    br := bufio.NewReader(f)\n    br.ReadByte() // scan to next 0x47\n    demuxer.Reset(br)\n}\npid, start, err := demuxer.ReadPacket()","handlingStrategy":"validation","validationCode":"func isTSSynced(data []byte, off int) bool {\n\t// 0x47 at packet boundaries of 188 bytes confirms real MPEG-TS alignment\n\tfor i := 0; i < 3; i++ {\n\t\tp := off + i*188\n\t\tif p >= len(data) || data[p] != 0x47 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n// scan data until isTSSynced returns true before handing the reader to the demuxer","typeGuard":null,"tryCatchPattern":"if _, _, err := demuxer.ReadPacket(); err != nil && strings.Contains(err.Error(), \"wrong sync byte\") {\n\tlog.Warn(\"mpegts: desync detected, re-scanning for 0x47 sync byte\")\n\trd = resyncReader(rd) // skip bytes until 0x47 with 188-byte repetition\n\tdemuxer.Reset(rd)\n\tcontinue\n}","preventionTips":["Start reading exactly at a packet boundary (file start / response body start); never seek to arbitrary offsets","Validate the first byte is 0x47 and that it repeats every 188 bytes before demuxing","For UDP/unreliable sources, account for packet loss — a single dropped byte desyncs the whole stream","Confirm the payload is MPEG-TS and not MPEG-PS/MP4, which share extensions but lack the 0x47 alignment"],"tags":["mpegts","demuxer","sync-byte","corrupt-stream","streaming"],"backgroundTag":"invalid-argument-format","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}