AlexxIT/go2rtc · error
magic: unsupported header:
Error message
magic: unsupported header:
What it means
magic.Open is the format auto-detector: it peeks the first 4 bytes and dispatches to a known producer (Annex-B bitstream, WAV, Y4M, FLV, MJPEG, AAC, mpjpeg, MPEG-TS). If none of the magic signatures match — and no JPEG SOI/DB marker appears within the first 4096 bytes — it gives up and returns this error with the first 4 bytes hex-encoded, since it cannot determine which producer handles the input.
Solutions
- Check the hex value in the message against known signatures to identify the actual format (e.g. 66747970 = 'ftyp' means MP4), then use the appropriate producer or convert the stream first.
- Verify the URL/endpoint actually serves the expected raw stream and not an HTML/JSON error page — curl the endpoint and inspect the first bytes.
- Convert unsupported input with ffmpeg to a supported raw format, e.g. `ffmpeg -i input -c:v libx264 -f h264 -` for an Annex-B H.264 pipe.
- If the stream is MJPEG with more than 4096 bytes of leading garbage, strip the leading bytes yourself before passing the reader to magic.Open.
Example fix
// before
resp, _ := http.Get(url)
p, err := magic.Open(resp.Body) // error: magic: unsupported header: 3c68746d ("<htm")
// after: check content type / let ffmpeg transcode to a supported pipe
cmd := exec.Command("ffmpeg", "-i", url, "-c", "copy", "-f", "h264", "-")
stdout, _ := cmd.StdoutPipe()
cmd.Start()
p, err := magic.Open(stdout) Defensive patterns
Strategy: try-catch
Validate before calling
func sniffSupported(rd io.Reader) (bool, error) {
b, err := bufio.NewReader(rd).Peek(4)
if err != nil {
return false, err
}
sig := map[string]bool{"\x00\x00\x00\x01": true, "RIFF": true, "YUV4": true, "FLV\x01": true, "\xFF\xD8": true, "\xFF\xF1": true, "\xFF\xF9": true, "--": true, "\x47": true}
return sig[string(b[:1])] || sig[string(b[:2])] || sig[string(b[:3])] || sig[string(b)], nil
} Try / catch
p, err := magic.Open(rd)
if err != nil && strings.Contains(err.Error(), "magic: unsupported header") {
log.Warnf("unknown format, header=%s, falling back to ffmpeg transcode", err.Error())
p, err = openViaFFmpeg(source) // ffmpeg -i src -c copy -f mpegts -
} Prevention
- Check the hex header in the error against known signatures to identify the true container
- curl -v the source URL and inspect the first bytes to rule out HTML/JSON error pages
- Prefer explicitly specifying the source format instead of relying on auto-detection for exotic streams
- Keep leading-garbage workarounds within the 4096-byte MJPEG sniff window or strip padding yourself
When it happens
Trigger: Calling magic.Open on a reader whose first bytes are not one of the supported signatures: an MP4/MOV container, WebM/Matroska, raw PCM, ADTS with different framing, gzip-compressed stream, an HTTP body containing HTML error page, or a stream that starts with padding/garbage beyond the 4096-byte MJPEG recovery window.
Common situations: Using go2rtc source `magic:` with a URL that returns an error page instead of media; pointing at an MP4 file expecting live-stream detection; TLS endpoint returning binary handshake garbage; camera stream that is actually MPEG-PS or another proprietary format; network truncation yielding a short/garbled prefix.
Related errors
- producer without tracks
- wrong status:
- ivideon: wrong message type:
- bitstream: unsupported header:
- mpegts: wrong sync byte
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/3a26aefce97d39e9.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/magic/producer.go:68
}
switch b[0] {
case mpegts.SyncByte:
return mpegts.Open(rd)
}
// support MJPEG with trash on start
// https://github.com/AlexxIT/go2rtc/issues/747
if b, err = rd.Peek(4096); err != nil {
return nil, err
}
if i := bytes.Index(b, []byte{0xFF, 0xD8, 0xFF, 0xDB}); i > 0 {
_, _ = io.ReadFull(rd, make([]byte, i))
return mjpeg.Open(rd)
}
return nil, errors.New("magic: unsupported header: " + hex.EncodeToString(b[:4]))
}
View on GitHub (pinned to c245815e75)