AlexxIT/go2rtc · error

mjpeg: no receivers

Error message

mjpeg: no receivers

What it means

An MJPEG Producer must have exactly one receiver (codec consumer) attached before Start is called; it reads the multipart stream from the transport and pushes frames into that single receiver. If Receivers is empty or has more than one entry, the producer cannot route frames and refuses to start.

Solutions

  1. Attach exactly one MJPEG consumer/receiver to the producer before calling Start.
  2. Check pipeline ordering: create the consumer first, then the producer, then start.
  3. Inspect why receivers were removed — a previously-attached consumer that errored out may have deregistered itself; fix the consumer's error first.
  4. Log len(producer.Receivers) just before Start to confirm the wiring.

Example fix

// before
producer, _ := mpjpeg.NewProducer(transport)
producer.Start()
// after
producer, _ := mpjpeg.NewProducer(transport)
producer.AddConsumer(mjpegConsumer)
producer.Start()
Defensive patterns

Strategy: validation

Validate before calling

if producer == nil || len(producer.Receivers) != 1 {
    return errors.New("producer requires exactly one receiver before Start")
}

Type guard

func startable(p *mpjpeg.Producer) bool {
    return p != nil && len(p.Receivers) == 1
}

Try / catch

if err := producer.Start(); err != nil {
    if strings.Contains(err.Error(), "no receivers") {
        // re-attach consumer and retry once
        producer.Receivers = []interface{}{consumer}
        return producer.Start()
    }
    return err
}

Prevention

When it happens

Trigger: Calling Producer.Start() when c.Receivers has a length other than 1 — i.e. the producer was built without an attached consumer, or with multiple consumers.

Common situations: Custom pipeline code that forgot to wire a receiver before starting the producer; a consumer that already exited and removed itself, leaving zero receivers; framework misuse building the producer manually instead of through the standard consumer API.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/ddeee48292e2e7af. Report an issue: GitHub.

Appendix: source

Thrown at pkg/mpjpeg/producer.go:42

				{
					Kind:      core.KindVideo,
					Direction: core.DirectionRecvonly,
					Codecs: []*core.Codec{
						{
							Name:        core.CodecJPEG,
							ClockRate:   90000,
							PayloadType: core.PayloadTypeRAW,
						},
					},
				},
			},
		},
	}, nil
}

func (c *Producer) Start() error {
	if len(c.Receivers) != 1 {
		return errors.New("mjpeg: no receivers")
	}

	rd := bufio.NewReader(c.Transport.(io.Reader))

	mjpeg := c.Receivers[0]

	for {
		_, body, err := Next(rd)
		if err != nil {
			return err
		}

		c.Recv += len(body)

		if mjpeg != nil {
			packet := &rtp.Packet{
				Header:  rtp.Header{Timestamp: core.Now90000()},
				Payload: body,

View on GitHub (pinned to c245815e75)