AlexxIT/go2rtc · error

connection is nil

Error message

connection is nil

What it means

StartIntercom enables two-way talk by opening the return-audio (speaker) channel on the Wyze camera. This error is returned when c.conn is nil, meaning Dial() has not completed (or failed) before StartIntercom was called. The library refuses to write control commands on a non-existent connection.

Solutions

  1. Call client.Dial() and check its error before calling StartIntercom.
  2. Serialize setup so AddTrack/StartIntercom only run after connection is established (sync.Once, channel signal, or callback from Dial).
  3. If reconnecting, re-run Dial and re-check conn != nil before retrying intercom.

Example fix

// before
go client.Dial()
client.StartIntercom()

// after
if err := client.Dial(); err != nil {
    return err
}
if err := client.StartIntercom(); err != nil {
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

if client == nil || !client.IsConnected() {
    return fmt.Errorf("wyze client not connected; call Dial first")
}
return client.StartIntercom()

Type guard

func ready(c *wyze.Client) bool { return c != nil && c.IsConnected() }

Prevention

When it happens

Trigger: Calling StartIntercom (directly or via AddTrack) before Dial() succeeds, after Dial() returned an error, or on a Client that was constructed but never connected. Also if a previous disconnect set conn to nil.

Common situations: Race between WebRTC track negotiation and camera connection; forgot to call Dial() first; Dial() failed silently in a goroutine and the caller proceeded; reconnect logic left the client in a disconnected state.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at pkg/wyze/client.go:206

	_, err := c.conn.WriteAndWaitIOCtrl(k10056, c.matchHL(KCmdSetResolutionResp), 5*time.Second)
	return err
}

func (c *Client) StartVideo() error {
	k10010 := c.buildK10010(MediaTypeVideo, true)
	_, err := c.conn.WriteAndWaitIOCtrl(k10010, c.matchHL(KCmdControlChannelResp), 5*time.Second)
	return err
}

func (c *Client) StartAudio() error {
	k10010 := c.buildK10010(MediaTypeAudio, true)
	_, err := c.conn.WriteAndWaitIOCtrl(k10010, c.matchHL(KCmdControlChannelResp), 5*time.Second)
	return err
}

func (c *Client) StartIntercom() error {
	if c.conn == nil {
		return fmt.Errorf("connection is nil")
	}

	if c.conn.IsBackchannelReady() {
		return nil
	}

	k10010 := c.buildK10010(MediaTypeReturnAudio, true)
	if _, err := c.conn.WriteAndWaitIOCtrl(k10010, c.matchHL(KCmdControlChannelResp), 5*time.Second); err != nil {
		return fmt.Errorf("enable return audio: %w", err)
	}

	if c.verbose {
		fmt.Printf("[Wyze] Speaker channel enabled, waiting for readiness...\n")
	}

	return c.conn.AVServStart()
}

View on GitHub (pinned to c245815e75)