{"record":{"id":"e345998e9e03c2f9","repo":"AlexxIT/go2rtc","slug":"multipart-wrong-boundary","errorCode":null,"errorMessage":"multipart: wrong boundary: ","messagePattern":"multipart: wrong boundary: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/mpjpeg/multipart.go","lineNumber":26,"sourceCode":"\t\"net/textproto\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc Next(rd *bufio.Reader) (http.Header, []byte, error) {\n\tfor {\n\t\t// search next boundary and skip empty lines\n\t\ts, err := rd.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif s == \"\\r\\n\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !strings.HasPrefix(s, \"--\") {\n\t\t\treturn nil, nil, errors.New(\"multipart: wrong boundary: \" + s)\n\t\t}\n\n\t\t// Foscam G2 has a awful implementation of MJPEG\n\t\t// https://github.com/AlexxIT/go2rtc/issues/1258\n\t\tif b, _ := rd.Peek(2); string(b) == \"--\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\n\ttp := textproto.NewReader(rd)\n\theader, err := tp.ReadMIMEHeader()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\ts := header.Get(\"Content-Length\")","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/mpjpeg/multipart.go#L8-L44","documentation":"go2rtc's MJPEG-over-HTTP (multipart/jpeg) reader expects each part separator line of the multipart stream to start with \"--\" (the boundary prefix). If a line read before a part does not look like a boundary delimiter, the server is not speaking the expected multipart format, so Next fails with the offending line appended to the message.","triggerScenarios":"Calling Producer.Start (via mpjpeg probe) against an HTTP endpoint whose response body lines between JPEG frames do not begin with \"--boundary\" — e.g. the server sent an error page, HTML, or a non-multipart body.","commonSituations":"Wrong URL pointing to a snapshot page or HTML error page instead of the MJPEG stream; camera returning HTTP 200 with an error body; firmware quirks (e.g. Foscam cameras sending odd separators, see go2rtc issue #1258); proxy stripping multipart framing.","solutions":["Verify the URL is the actual MJPEG stream endpoint (often /video.mjpg or /mjpg/video.mjpeg), not a snapshot or admin page.","Check the camera's HTTP response with curl (`curl -s URL | head`) to confirm it returns multipart/jpeg with boundary lines.","Update go2rtc — known vendor quirks (Foscam G2) have workarounds added.","Confirm the camera requires authentication; an unauthenticated request may return an HTML login page that fails this check."],"exampleFix":"// before: pointing at snapshot endpoint\nurl := \"http://camera/ipcam.jpg\"\n// after: use the MJPEG stream endpoint\nurl := \"http://camera/mjpg/video.mjpeg\"","handlingStrategy":"validation","validationCode":"resp, _ := http.Get(url)\nct := resp.Header.Get(\"Content-Type\")\nif !strings.HasPrefix(ct, \"multipart/x-mixed-replace\") {\n    return fmt.Errorf(\"expected multipart stream, got %s\", ct)\n}","typeGuard":null,"tryCatchPattern":"producer, err := mpjpeg.NewProducer(transport)\nif err != nil {\n    if strings.Contains(err.Error(), \"wrong boundary\") {\n        return fmt.Errorf(\"URL is not an MJPEG multipart stream; check endpoint and auth: %w\", err)\n    }\n    return err\n}","preventionTips":["Use the camera's documented MJPEG stream URL, not snapshot endpoints","curl the endpoint first and confirm boundary lines (--boundary) in the body","Include credentials so the server doesn't return an HTML login page","Keep go2rtc updated for vendor-specific multipart quirks"],"tags":["multipart","mjpeg","http-stream"],"backgroundTag":"unexpected-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"}