{"record":{"id":"c79522dfd9b409a5","repo":"AlexxIT/go2rtc","slug":"webrtc","errorCode":null,"errorMessage":"webrtc: ","messagePattern":"webrtc: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/webrtc/client.go","lineNumber":116,"sourceCode":"\tprod.Mode = core.ModeActiveProducer\n\tprod.Protocol = \"ws\"\n\tprod.URL = url\n\tprod.Listen(func(msg any) {\n\t\tswitch msg := msg.(type) {\n\t\tcase *pion.ICECandidate:\n\t\t\ts := msg.ToJSON().Candidate\n\t\t\tlog.Trace().Str(\"candidate\", s).Msg(\"[webrtc] local \")\n\t\t\tconnMu.Lock()\n\t\t\t_ = conn.WriteJSON(&ws.Message{Type: \"webrtc/candidate\", Value: s})\n\t\t\tconnMu.Unlock()\n\n\t\tcase pion.PeerConnectionState:\n\t\t\tswitch msg {\n\t\t\tcase pion.PeerConnectionStateConnecting:\n\t\t\tcase pion.PeerConnectionStateConnected:\n\t\t\t\tconnState.Done(nil)\n\t\t\tdefault:\n\t\t\t\tconnState.Done(errors.New(\"webrtc: \" + msg.String()))\n\t\t\t}\n\t\t}\n\t})\n\n\tmedias := []*core.Media{\n\t\t{Kind: core.KindVideo, Direction: core.DirectionRecvonly},\n\t\t{Kind: core.KindAudio, Direction: core.DirectionRecvonly},\n\t\t{Kind: core.KindAudio, Direction: core.DirectionSendonly},\n\t}\n\n\t// 3. Create offer\n\toffer, err := prod.CreateOffer(medias)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// 4. Send offer\n\tmsg := &ws.Message{Type: \"webrtc/offer\", Value: offer}","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/internal/webrtc/client.go#L98-L134","documentation":"During the WebRTC connection state change, the peer connection entered a state other than Connecting/Connected (failed, disconnected, closed, etc.). go2rtc signals completion with an error carrying pion's state string.","triggerScenarios":"ICE negotiation failing (no usable candidates), DTLS handshake failure, remote peer closing the connection, or network change aborting the session between answer exchange and media flow.","commonSituations":"Camera/serving behind NAT without a working STUN/TURN path; firewall blocking UDP; WHEP server rejecting the session after setup; timeout waiting for the remote side.","solutions":["Check that ICE servers (STUN/TURN) are configured and reachable from both ends","Verify UDP ports/firewall allow WebRTC traffic, or route through TURN","Confirm the WHEP/signaling server session is still valid (token expiry)","Read the appended state string (e.g. \"webrtc: failed\") to identify the exact pion state"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"prod, err := webrtcClient(url)\nif err != nil && strings.HasPrefix(err.Error(), \"webrtc: \") {\n\tstate := strings.TrimPrefix(err.Error(), \"webrtc: \")\n\tif state == \"failed\" || state == \"disconnected\" {\n\t\t// exponential backoff retry with fresh offer\n\t}\n}","preventionTips":["Configure reachable STUN/TURN servers","Allow UDP traffic through firewalls or force TURN","Validate signaling tokens are fresh before connecting"],"tags":["go","webrtc","ice","network"],"backgroundTag":"connection-failed","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}