AlexxIT/go2rtc · error
api.StreamNotFound
Error message
api.StreamNotFound
What it means
The MJPEG WebSocket handler (handlerWS) looks up the stream named by the request's query parameters via streams.GetOrPatch. If no stream with that name exists (nil result), it returns the api.StreamNotFound error, refusing to create the MJPEG consumer.
Solutions
- Ensure the WS URL query includes src=<existing stream name> exactly as configured
- Verify the stream exists in go2rtc.yaml or was created via the streams API before connecting
- Check for typos and case differences in the stream name
- Confirm go2rtc reloaded the config after adding the stream
Example fix
// before
new WebSocket("ws://host:1984/api/ws?src=camm")
// after
new WebSocket("ws://host:1984/api/ws?src=cam") Defensive patterns
Strategy: validation
Validate before calling
// JS: verify the stream exists before opening WS/MJPEG
const res = await fetch(`http://host:1984/api/streams?src=${name}`)
if (!(await res.ok)) throw new Error(`stream ${name} not found`)
const ws = new WebSocket(`ws://host:1984/api/ws?src=${name}`) Try / catch
// JS
ws.onerror = (e) => console.error('mjpeg ws failed — check src stream name:', e)
ws.onclose = (ev) => { if (ev.code === 1006) checkStreamExists() } Prevention
- Keep stream names in a shared constant/config between backend and frontend
- Validate the src parameter against the /api/streams list before connecting
- Handle stream renames centrally in the frontend
When it happens
Trigger: Opening a WS/MJPEG connection with a ?src=name query parameter that doesn't match any configured or dynamically created stream; empty or misspelled src parameter.
Common situations: Frontend JS pointing at a stream name that was renamed or removed from go2rtc.yaml, case-sensitive name mismatch, or forgetting the src query parameter entirely.
Related errors
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/13a4cf03a982855f.
Report an issue: GitHub.
Appendix: source
Thrown at internal/mjpeg/mjpeg.go:196
return
}
prod, _ := mpjpeg.Open(r.Body)
prod.WithRequest(r)
stream.AddProducer(prod)
if err := prod.Start(); err != nil && err != io.EOF {
log.Warn().Err(err).Caller().Send()
}
stream.RemoveProducer(prod)
}
func handlerWS(tr *ws.Transport, _ *ws.Message) error {
stream, _ := streams.GetOrPatch(tr.Request.URL.Query())
if stream == nil {
return errors.New(api.StreamNotFound)
}
cons := mjpeg.NewConsumer()
cons.WithRequest(tr.Request)
if err := stream.AddConsumer(cons); err != nil {
log.Debug().Err(err).Msg("[mjpeg] add consumer")
return err
}
tr.Write(&ws.Message{Type: "mjpeg"})
go cons.WriteTo(tr.Writer())
tr.OnClose(func() {
stream.RemoveConsumer(cons)
})
View on GitHub (pinned to c245815e75)