livekit/livekit · warning

cannot start on rtx packet

Error message

cannot start on rtx packet

What it means

The stream buffer refuses to begin RTP stats tracking when the first packet processed is a retransmission (RTX) while rtpStats is not yet active. Starting a stream on an RTX packet would corrupt sequence-number accounting because the original sequence number belongs to an earlier stream position.

Source

Thrown at pkg/sfu/buffer/buffer_base.go:779

			if flowState.UnhandledReason == rtpstats.RTPFlowUnhandledReasonNone && !flowState.IsOutOfOrder {
				if err := b.snRangeMap.ExcludeRange(flowState.ExtSequenceNumber, flowState.ExtSequenceNumber+1); err != nil {
					b.logger.Errorw(
						"could not exclude range", err,
						"sequenceNumber", sn,
						"extSequenceNumber", flowState.ExtSequenceNumber,
						"rtpStats", b.rtpStats,
						"rtpStatsLite", b.rtpStatsLite,
						"snRangeMap", b.snRangeMap,
						"skipped", skippedSeqs,
					)
				}
			}
		}
	}

	// do not start on an RTX packet
	if isRTX && !b.rtpStats.IsActive() {
		return 0, errors.New("cannot start on rtx packet")
	}

	flowState := b.rtpStats.Update(
		arrivalTime,
		rtpPacket.Header.SequenceNumber,
		rtpPacket.Header.Timestamp,
		rtpPacket.Header.Marker,
		rtpPacket.Header.MarshalSize(),
		len(rtpPacket.Payload),
		int(rtpPacket.Header.PaddingSize),
	)
	switch flowState.UnhandledReason {
	case rtpstats.RTPFlowUnhandledReasonNone:
	case rtpstats.RTPFlowUnhandledReasonRestart:
		if !b.enableStreamRestartDetection {
			return 0, fmt.Errorf("unhandled reason: %s", flowState.UnhandledReason.String())
		}

View on GitHub (pinned to ee45c3f0b1)

Solutions

  1. Usually transient: the next non-RTX packet initializes the stream; retry/let the track re-buffer.
  2. Check publisher uplink quality — persistent early RTX indicates pre-join loss.
  3. Upgrade LiveKit; RTX handling/repair logic has been improved across releases.
  4. If reproducible, capture publisher-side traces to confirm RTX-before-original ordering.
Defensive patterns

Strategy: retry

Try / catch

// SFU-internal: treat as transient stream-start failure
if err := buffer.Read(...); errors.Is(err, errCannotStartOnRTX) {
  // wait for next non-RTX packet; do not tear down the track
  continue
}

Prevention

When it happens

Trigger: A subscriber/track begins being forwarded and the first packet arriving at the buffer is an RTX retransmission (matched via the RTX SN cache or SN offset heuristic) before any original packet initializes stats.

Common situations: Joining a room mid-stream with packet loss where the very first received packet is a retransmission; publisher-side network producing RTX before original packets reach the SFU; track restart/reconnect scenarios.

Related errors


AI-assisted analysis of livekit/livekit@ee45c3f0b1 (2026-09-02). Data as JSON: /api/errors/de0d3fe9341d2903. Report an issue: GitHub.