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

  1. Read the state suffix in the message (e.g. "ring: failed") to identify the WebRTC failure
  2. Ensure ICE/STUN connectivity to the Ring camera network
  3. Refresh credentials and retry the dial
  4. 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

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)