Learning objective. Explain how QUIC recovers data that acknowledgments alone cannot flag as lost: the probe timeout, why it sends probes rather than blind retransmissions, and why it does not, by itself, cut the sending rate.
Two ways to trigger a resend #
QUIC resends the frames from a lost packet in a new packet (§3.1); the only question is what triggers it. There are two triggers. The first, covered already, is acknowledgment-based loss detection: a later packet is acked, and the packet or time threshold marks an earlier one lost. This handles the common case cheaply. But it needs acknowledgments to arrive. If the last packets of a flight are lost, or the network goes quiet, no ACK comes and there is nothing to compare against. That is what the second trigger, the probe timeout, exists for.
The probe timeout (PTO) #
Whenever ack-eliciting packets are in flight, the sender arms a PTO timer ([RFC 9002 §6.2]):
PTO = smoothed_rtt + max(4 * rttvar, kGranularity) + max_ack_delay
The max(4 * rttvar, kGranularity) term budgets for RTT variation (floored at 1 ms), and
max_ack_delay accounts for the receiver's own acknowledgment delay, though it is
included only once the handshake is confirmed, since Initial and Handshake packets are
acked promptly. Before any RTT sample exists, smoothed_rtt starts at kInitialRtt (333
ms) with rttvar = kInitialRtt / 2 ([RFC 9002 §6.2.2]). Each time the PTO fires without
progress, it backs off exponentially: the timer doubles per consecutive expiry, so a
truly dead path is probed ever more sparingly rather than flooded.
Probes, not blind retransmissions #
The crucial design choice: when the PTO fires, the sender does not assume anything is lost. It sends one or two probe packets (ack-eliciting packets, which may carry new data or resend old frames) whose only job is to elicit an acknowledgment ([RFC 9002 §6.2.4]). When that ACK comes back, ordinary loss detection (§3.1) runs and marks whatever is genuinely missing. Probes are even allowed to exceed the congestion window temporarily, so a PTO can always make progress.
This leads to the difference that most surprises engineers coming from TCP: a PTO does not reduce the congestion window. TCP's RTO collapses the window to one segment on every timeout; QUIC treats the PTO purely as a prompt for information. Only confirmed loss, detected from the ACK the probe elicits, reduces the window (§3.3). A single spurious timeout on a jittery path therefore costs a probe packet, not a throughput collapse.
The one case where a timeout does cut the window hard is persistent congestion: if a
span of time covering at least kPersistentCongestionThreshold (3) PTOs is entirely lost
(established once an ACK finally arrives), the sender concludes the path genuinely failed and
collapses the window to kMinimumWindow. That is a deliberate, evidence-backed reaction,
not a reflex to one silent timer; it is detailed in §3.3.
editorial Tail loss means losing the final packets of a
response, with no following packet to trigger threshold detection. That is exactly what the PTO
rescues, and it is common for small objects. If a capture shows a request that stalls for
roughly one PTO and then completes, you are almost certainly watching probe-driven
recovery, not a server that was slow. Keeping max_ack_delay honest and RTT samples
flowing (via steady acknowledgments, §3.1) keeps the PTO tight so that
recovery is fast rather than a visible pause.
Takeaways #
Loss detection handles losses that acknowledgments can reveal; the PTO covers the rest by probing for information when the network falls silent, backing off on a dead path, and — critically — leaving the congestion window alone until real loss is confirmed. What that confirmed loss then does to the sending rate is the subject of §3.3: congestion control.