AlexxIT/go2rtc · error

producer without tracks

Error message

producer without tracks

What it means

Client.Start checks that the Receivers slice is populated before starting playback; the (misleadingly named) 'producer without tracks' error means the client has no receivers/tracks configured, so there is nothing to start. The library refuses to start a client with an empty media configuration.

Solutions

  1. Ensure receivers/tracks are configured on the Client before calling Start() (populate Client.Receivers, e.g. via negotiation or explicit setup)
  2. Verify the upstream negotiation (SDP/camera stream setup) succeeded and returned at least one receiver
  3. Check that Medias/codecs are defined so receiver initialization code actually runs
  4. Guard the Start() call with a check like if client.Receivers == nil || len(client.Receivers) == 0 { configure first }

Example fix

// before
client, _ := homekit.NewClient(...)
err := client.Start() // panics into 'producer without tracks'
// after
client, _ := homekit.NewClient(...)
if len(client.GetMedias()) == 0 {
    return errors.New("no media configured for homekit client")
}
err := client.Start()
Defensive patterns

Strategy: validation

Validate before calling

if client.Receivers == nil || len(client.Receivers) == 0 {
    return errors.New("cannot start homekit client: no receivers configured")
}
if err := client.Start(); err != nil { return err }

Type guard

func hasReceivers(c *homekit.Client) bool {
    return c != nil && c.Receivers != nil && len(c.Receivers) > 0
}

Try / catch

if err := client.Start(); err != nil {
    if strings.Contains(err.Error(), "producer without tracks") {
        return fmt.Errorf("homekit client has no receivers/tracks; run negotiation first: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Start() on a homekit Client constructed without adding any receivers/tracks (e.g. Receivers nil because no stream/codec was negotiated or configured), or after a failed negotiation that left Receivers unset.

Common situations: Streaming a camera to HomeKit where the session was never properly negotiated; wiring a Client before codecs/receivers were assigned; a code path that skips receiver setup for unsupported codecs.

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/2500e8c1a067d014. Report an issue: GitHub.

Appendix: source

Thrown at pkg/homekit/producer.go:112

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

	return c.Medias
}

func (c *Client) Start() error {
	if c.Receivers == nil {
		return errors.New("producer without tracks")
	}

	if c.Receivers[0].Codec.Name == core.CodecJPEG {
		return c.startMJPEG()
	}

	videoTrack := c.trackByKind(core.KindVideo)
	videoCodec := trackToVideo(videoTrack, &c.videoConfig.Codecs[0], c.MaxWidth, c.MaxHeight)

	audioTrack := c.trackByKind(core.KindAudio)
	audioCodec := trackToAudio(audioTrack, &c.audioConfig.Codecs[0])

	c.videoSession = &srtp.Session{Local: c.srtpEndpoint()}
	c.audioSession = &srtp.Session{Local: c.srtpEndpoint()}

	var err error
	c.stream, err = camera.NewStream(c.hap, videoCodec, audioCodec, c.videoSession, c.audioSession, c.Bitrate)
	if err != nil {

View on GitHub (pinned to c245815e75)