{"record":{"id":"c4e8babf0b01d772","repo":"cloudflare/cloudflared","slug":"failed-to-send-datagram-back-to-edge","errorCode":null,"errorMessage":"Failed to send datagram back to edge","messagePattern":"Failed to send datagram back to edge","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quic/datagram.go","lineNumber":56,"sourceCode":"\t}\n}\n\n// Maximum application payload to send to / receive from QUIC datagram frame\nfunc (dm *DatagramMuxer) mtu() int {\n\treturn maxDatagramPayloadSize\n}\n\nfunc (dm *DatagramMuxer) SendToSession(session *packet.Session) error {\n\tif len(session.Payload) > dm.mtu() {\n\t\tpacketTooBigDropped.Inc()\n\t\treturn fmt.Errorf(\"origin UDP payload has %d bytes, which exceeds transport MTU %d\", len(session.Payload), dm.mtu())\n\t}\n\tpayloadWithMetadata, err := SuffixSessionID(session.ID, session.Payload)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"Failed to suffix session ID to datagram, it will be dropped\")\n\t}\n\tif err := dm.session.SendDatagram(payloadWithMetadata); err != nil {\n\t\treturn errors.Wrap(err, \"Failed to send datagram back to edge\")\n\t}\n\treturn nil\n}\n\nfunc (dm *DatagramMuxer) ServeReceive(ctx context.Context) error {\n\tfor {\n\t\t// Extracts datagram session ID, then sends the session ID and payload to receiver\n\t\t// which determines how to proxy to the origin. It assumes the datagram session has already been\n\t\t// registered with receiver through other side channel\n\t\tmsg, err := dm.session.ReceiveDatagram(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := dm.demux(ctx, msg); err != nil {\n\t\t\tdm.logger.Error().Err(err).Msg(\"Failed to demux datagram\")\n\t\t\tif err == context.Canceled {\n\t\t\t\treturn err\n\t\t\t}","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/quic/datagram.go#L38-L74","documentation":"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.","triggerScenarios":"dm.session.SendDatagram(payloadWithMetadata) returns an error — QUIC connection closed, datagram queue full (flow control/backpressure), or the connection is shutting down.","commonSituations":"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.","solutions":["Confirm the tunnel is connected (cloudflared metrics/logs for reconnect events); the error is usually transient during reconnects.","Retry the UDP exchange from the client — UDP under cloudflared is lossy by design; applications must tolerate drops.","Reduce UDP send rate if the datagram queue is overflowing (backpressure from a traffic burst).","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)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check tunnel connectivity before streaming UDP\nif !tunnelConnected() {\n    return errors.New(\"tunnel to edge is down; defer UDP sends\")\n}","typeGuard":null,"tryCatchPattern":"if err := muxer.SendToSession(datagram); err != nil {\n    if strings.Contains(err.Error(), \"send datagram back to edge\") {\n        select {\n        case <-time.After(50 * time.Millisecond):\n            return retrySend(datagram) // transient edge disconnect\n        case <-ctx.Done():\n            return ctx.Err()\n        }\n    }\n    return err\n}","preventionTips":["Design UDP applications to tolerate packet loss — the tunnel does not guarantee delivery.","Monitor QUIC reconnect events in cloudflared logs/metrics.","Rate-limit UDP bursts so the datagram send queue does not overflow.","Test with --protocol http2 if your network path destabilizes QUIC."],"tags":["quic","udp","datagram","edge","packet-drop"],"backgroundTag":"network-request-failed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}