WebRTC Metrics

A comprehensive overview of WebRTC statistics, derived calculations, extracted features, and observable signals, to better understand call quality, connectivity, and user experience in rtcStats

Back
On this page5 sections
connectivitybugsignalingErrortype

Signaling error

Last updated Applies tortcstats-enrichmentrtcstats.com

A signaling operation (createOffer, createAnswer, setLocalDescription, setRemoteDescription, or addIceCandidate) was rejected. This can happen when the peer connection is closed, the signaling state does not allow the attempted operation, or an internal resource/negotiation failure occurs.

Description

The rtcstats-js instrumentation wraps five RTCPeerConnection methods and traces an <method>OnFailure event whenever the returned promise rejects: createOffer, createAnswer, setLocalDescription, setRemoteDescription, and addIceCandidate. This observation fires when any of them rejects.

A rejection here is not the same as a negotiated-but-degraded outcome. Per the W3C WebRTC specification, a lack of common codecs or other m-line mismatches between offer and answer still resolves the promise (the incompatible media section is marked as rejected in the resulting SDP); it does not throw. A rejection instead points to the peer connection being closed, an invalid signaling state for the attempted operation, or an internal resource or negotiation failure.

Is it a problem?

It depends on when it happens:

  • Teardown races: a failure that lands right after close() or a connectionstatechange to closed is usually benign, the application tore down the connection while an async operation was still in flight.
  • A pre-answer addIceCandidate race: a remote candidate arriving before the first setRemoteDescription completes can reject with an InvalidStateError, which is a timing issue rather than a fault.
  • Anything else: a rejection during active negotiation (not close-adjacent, not a pre-answer candidate race) usually means the application called an operation while the peer connection was in the wrong signaling state, or hit a genuine negotiation/resource failure.

This observation does not yet distinguish these cases: every qualifying failure is reported at high severity regardless of context. Filtering out the benign teardown and pre-answer cases is tracked separately.

When does it trigger?

Any of the five *OnFailure trace entries for a peer connection produces exactly one signalingError observation for that peer connection. The observation's property carries the name of the first failing operation, firstSeenAt is the timestamp of the chronologically first occurrence, and valueInCount is the total number of failures across all five operations combined for that peer connection.

What do we do here?

We scan each peer connection's log for createOfferOnFailure, createAnswerOnFailure, setLocalDescriptionOnFailure, setRemoteDescriptionOnFailure, and addIceCandidateOnFailure entries and report one signalingError observation per peer connection when at least one is found.