AlexxIT/go2rtc · error
mpegts: wrong sync byte
Error message
mpegts: wrong sync byte
What it means
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.
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.
Example fix
// before: reading from an offset mid-packet
f.Seek(137, 0)
pid, start, err := demuxer.ReadPacket() // wrong sync byte
// after: re-align to the next 0x47 sync byte
f.Seek(137, 0)
b, _ := f.Peek(1)
if b[0] != 0x47 {
br := bufio.NewReader(f)
br.ReadByte() // scan to next 0x47
demuxer.Reset(br)
}
pid, start, err := demuxer.ReadPacket() Defensive patterns
Strategy: validation
Validate before calling
func isTSSynced(data []byte, off int) bool {
// 0x47 at packet boundaries of 188 bytes confirms real MPEG-TS alignment
for i := 0; i < 3; i++ {
p := off + i*188
if p >= len(data) || data[p] != 0x47 {
return false
}
}
return true
}
// scan data until isTSSynced returns true before handing the reader to the demuxer Try / catch
if _, _, err := demuxer.ReadPacket(); err != nil && strings.Contains(err.Error(), "wrong sync byte") {
log.Warn("mpegts: desync detected, re-scanning for 0x47 sync byte")
rd = resyncReader(rd) // skip bytes until 0x47 with 188-byte repetition
demuxer.Reset(rd)
continue
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- mpegts: wrong adaptation size
- producer without tracks
- wrong status:
- ivideon: wrong message type:
- bitstream: unsupported header:
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/bff3ca8f82442394.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/mpegts/demuxer.go:74
pkt.Payload = append(pkt.Payload, pes.StreamType)
}
return pkt, nil
}
continue
}
if pkt := d.readPES(pid, start); pkt != nil {
return pkt, nil
}
}
}
func (d *Demuxer) readPacketHeader() (pid uint16, start bool, err error) {
d.reset()
sb := d.readByte() // Sync byte
if sb != SyncByte {
return 0, false, errors.New("mpegts: wrong sync byte")
}
_ = d.readBit() // Transport error indicator (TEI)
pusi := d.readBit() // Payload unit start indicator (PUSI)
_ = d.readBit() // Transport priority
pid = d.readBits16(13) // PID
_ = d.readBits(2) // Transport scrambling control (TSC)
af := d.readBit() // Adaptation field
_ = d.readBit() // Payload
_ = d.readBits(4) // Continuity counter
if af != 0 {
adSize := d.readByte() // Adaptation field length
if adSize > PacketSize-6 {
return 0, false, errors.New("mpegts: wrong adaptation size")
}
d.skip(adSize)View on GitHub (pinned to c245815e75)