cloudflare/cloudflared · error

Failed to send datagram back to edge

Error message

Failed to send datagram back to edge

What it means

In quic/datagram.go SendToSession, after the session ID is successfully suffixed, the payload is handed to dm.session.SendDatagram to ship over the QUIC connection to Cloudflare's edge. Failure here means the QUIC connection itself refused or could not queue the datagram, and the UDP packet is lost.

Source

Thrown at quic/datagram.go:56

	}
}

// Maximum application payload to send to / receive from QUIC datagram frame
func (dm *DatagramMuxer) mtu() int {
	return maxDatagramPayloadSize
}

func (dm *DatagramMuxer) SendToSession(session *packet.Session) error {
	if len(session.Payload) > dm.mtu() {
		packetTooBigDropped.Inc()
		return fmt.Errorf("origin UDP payload has %d bytes, which exceeds transport MTU %d", len(session.Payload), dm.mtu())
	}
	payloadWithMetadata, err := SuffixSessionID(session.ID, session.Payload)
	if err != nil {
		return errors.Wrap(err, "Failed to suffix session ID to datagram, it will be dropped")
	}
	if err := dm.session.SendDatagram(payloadWithMetadata); err != nil {
		return errors.Wrap(err, "Failed to send datagram back to edge")
	}
	return nil
}

func (dm *DatagramMuxer) ServeReceive(ctx context.Context) error {
	for {
		// Extracts datagram session ID, then sends the session ID and payload to receiver
		// which determines how to proxy to the origin. It assumes the datagram session has already been
		// registered with receiver through other side channel
		msg, err := dm.session.ReceiveDatagram(ctx)
		if err != nil {
			return err
		}
		if err := dm.demux(ctx, msg); err != nil {
			dm.logger.Error().Err(err).Msg("Failed to demux datagram")
			if err == context.Canceled {
				return err
			}

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Confirm the tunnel is connected (cloudflared metrics/logs for reconnect events); the error is usually transient during reconnects.
  2. Retry the UDP exchange from the client — UDP under cloudflared is lossy by design; applications must tolerate drops.
  3. Reduce UDP send rate if the datagram queue is overflowing (backpressure from a traffic burst).
  4. If persistent, check MTU/UDP path issues between cloudflared and the edge that could break the QUIC connection, or fall back to the http2 protocol (--protocol http2).
Defensive patterns

Strategy: retry

Validate before calling

// check tunnel connectivity before streaming UDP
if !tunnelConnected() {
    return errors.New("tunnel to edge is down; defer UDP sends")
}

Try / catch

if err := muxer.SendToSession(datagram); err != nil {
    if strings.Contains(err.Error(), "send datagram back to edge") {
        select {
        case <-time.After(50 * time.Millisecond):
            return retrySend(datagram) // transient edge disconnect
        case <-ctx.Done():
            return ctx.Err()
        }
    }
    return err
}

Prevention

When it happens

Trigger: dm.session.SendDatagram(payloadWithMetadata) returns an error — QUIC connection closed, datagram queue full (flow control/backpressure), or the connection is shutting down.

Common situations: Tunnel to edge temporarily disconnected or reconnecting; QUIC datagram send queue overflowed during a UDP traffic burst; cloudflared shutting down while UDP sessions are still active.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/c4e8babf0b01d772. Report an issue: GitHub.