cloudflare/cloudflared · error
failed to accept QUIC stream: %w
Error message
failed to accept QUIC stream: %w
What it means
acceptStream loops calling q.conn.AcceptStream(ctx) to receive streams the edge opens. If AcceptStream errors for any reason other than an intentional context cancellation or a stopped control stream, the error is wrapped as `failed to accept QUIC stream` and returned, ending the Serve errgroup and triggering reconnection.
Source
Thrown at connection/quic_connection.go:163
// serveControlStream will serve the RPC; blocking until the control plane is done.
func (q *quicConnection) serveControlStream(ctx context.Context, controlStream *quic.Stream) error {
return q.controlStreamHandler.ServeControlStream(ctx, controlStream, q.connOptions.ConnectionOptions(), q.orchestrator)
}
// Close the connection with no errors specified.
func (q *quicConnection) Close() {
_ = q.conn.CloseWithError(0, "")
}
func (q *quicConnection) acceptStream(ctx context.Context) error {
for {
quicStream, err := q.conn.AcceptStream(ctx)
if err != nil {
// context.Canceled is usually a user ctrl+c. We don't want to log an error here as it's intentional.
if errors.Is(err, context.Canceled) || q.controlStreamHandler.IsStopped() {
return nil
}
return fmt.Errorf("failed to accept QUIC stream: %w", err)
}
go q.runStream(quicStream)
}
}
func (q *quicConnection) runStream(quicStream *quic.Stream) {
ctx := quicStream.Context()
stream := cfdquic.NewSafeStreamCloser(quicStream, q.streamWriteTimeout, q.logger)
defer func() { _ = stream.Close() }()
// we are going to fuse readers/writers from stream <- cloudflared -> origin, and we want to guarantee that
// code executed in the code path of handleStream don't trigger an earlier close to the downstream write stream.
// So, we wrap the stream with a no-op write closer and only this method can actually close write side of the stream.
// A call to close will simulate a close to the read-side, which will fail subsequent reads.
noCloseStream := &nopCloserReadWriter{ReadWriteCloser: stream}
ss := rpcquic.NewCloudflaredServer(q.handleDataStream, q.datagramHandler, q, q.rpcTimeout)
if err := ss.Serve(ctx, noCloseStream); err != nil {
q.logger.Debug().Err(err).Msg("Failed to handle QUIC stream")View on GitHub (pinned to 2253eeeb25)
Solutions
- This is expected on reconnect cycles — verify the supervisor re-establishes the tunnel; otherwise restart cloudflared
- Check firewall/NAT settings for UDP 443 idle timeouts; keep QUIC sessions alive or use --protocol http2 over TCP
- Check network stability between the host and the nearest Cloudflare edge
- Upgrade cloudflared if errors recur immediately after handshake
Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "failed to accept QUIC stream") {
// supervisor should reconnect; log and rely on backoff
log.Warn().Err(err).Msg("QUIC stream accept failed; reconnecting")
} Prevention
- Prevent NAT/firewall from idle-expiring long-lived UDP sessions
- Monitor tunnel connectivity and alert on frequent accept failures
- Prefer --protocol http2 on unstable networks
- Restart cloudflared after network changes if reconnection stalls
When it happens
Trigger: AcceptStream returns a transport error: the QUIC connection was closed/reset by the edge, idle timeout expired, network dropped, or a QUIC protocol violation — while ctx is still live and the control stream hasn't been stopped.
Common situations: Long-lived idle tunnels killed by NAT/firewall UDP timeouts, edge-side connection resets during deployments, mobile/network switching, or abrupt tunnel termination from the Cloudflare dashboard.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- failed to open a registration control stream: %w
- payload length is too large to be bundled in datagram
- Failed to fetch resource
- packet with tracing context should have at least %d bytes, g
- timeout waiting for second stream to finish
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/9c84fd4979828eac.
Report an issue: GitHub.