AlexxIT/go2rtc · error
ring
Error message
ring: ${msg.String()} What it means
The ring client watches WebRTC peer connection state changes; any terminal state other than Connected (e.g. Failed, Closed, Disconnected) stops the client and completes the connection with this error containing the pion state string.
Solutions
- Read the state suffix in the message (e.g. "ring: failed") to identify the WebRTC failure
- Ensure ICE/STUN connectivity to the Ring camera network
- Refresh credentials and retry the dial
- Avoid calling Stop before the connection completes
Defensive patterns
Strategy: retry
Validate before calling
// no pre-call validation possible; ensure network allows UDP/STUN for WebRTC
if !udpConnectivityOK(stunServer) {
return errors.New("WebRTC connectivity required for ring streams")
} Try / catch
client, err := Dial(ctx, query)
if err != nil && strings.HasPrefix(err.Error(), "ring: ") {
state := strings.TrimPrefix(err.Error(), "ring: ")
log.Printf("peer connection ended in state %s, retrying", state)
client, err = Dial(ctx, query)
} Prevention
- Verify ICE/STUN/TURN connectivity in the deployment environment
- Don't reuse clients after Stop; create a fresh client per session
- Parse the pion state out of the message to branch on failure type
When it happens
Trigger: The pion PeerConnection transitions to a failed/closed/disconnected state during setup — ICE negotiation failure, no network path to the camera, or the peer connection being closed prematurely.
Common situations: Camera unreachable through NAT/firewall (ICE failure); Ring server rejecting the SDP offer; attempting to reuse a client after Stop was called.
Related errors
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/3872fb8542216e88.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/ring/client.go:163
"mlineindex": iceCandidate.SDPMLineIndex,
}
if err = client.wsClient.sendSessionMessage("ice", icePayload); err != nil {
client.connected.Done(err)
return
}
case pion.PeerConnectionState:
switch msg {
case pion.PeerConnectionStateNew:
break
case pion.PeerConnectionStateConnecting:
break
case pion.PeerConnectionStateConnected:
client.connected.Done(nil)
default:
client.Stop()
client.connected.Done(errors.New("ring: " + msg.String()))
}
}
})
client.prod = prod
// Setup media configuration
medias := []*core.Media{
{
Kind: core.KindAudio,
Direction: core.DirectionSendRecv,
Codecs: []*core.Codec{
{
Name: "opus",
ClockRate: 48000,
Channels: 2,
},
},View on GitHub (pinned to c245815e75)