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
- Ensure receivers/tracks are configured on the Client before calling Start() (populate Client.Receivers, e.g. via negotiation or explicit setup)
- Verify the upstream negotiation (SDP/camera stream setup) succeeded and returned at least one receiver
- Check that Medias/codecs are defined so receiver initialization code actually runs
- 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
- Only call Start() after a successful track/receiver negotiation
- Check GetMedias() returns at least one media before starting
- Log negotiation results so a silently empty receiver list is caught early
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
- api.StreamNotFound
- not homekit source
- homekit: can't work without SRTP server
- hap: no free streams
- hap: GetAccessories zero answer
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)