cloudflare/cloudflared · error

Failed to suffix session ID to datagram, it will be dropped

Error message

Failed to suffix session ID to datagram, it will be dropped

What it means

Same family as the datagram v1 case but in quic/datagramv2.go: SendToSession rejects oversized payloads, then appends the session ID via SuffixSessionID. If suffixing the session ID fails, the datagram is dropped and wrapped with this message. Version 2 additionally suffixes a datagram type byte afterwards.

Source

Thrown at quic/datagramv2.go:82

	logger := log.With().Uint8("datagramVersion", 2).Logger()
	return &DatagramMuxerV2{
		session:          quicSession,
		logger:           &logger,
		sessionDemuxChan: sessionDemuxChan,
		packetDemuxChan:  make(chan Packet, packetChanCapacity),
	}
}

// SendToSession suffix the session ID and datagram version to the payload so the other end of the QUIC connection can
// demultiplex the payload from multiple datagram sessions
func (dm *DatagramMuxerV2) 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())
	}
	msgWithID, err := SuffixSessionID(session.ID, session.Payload)
	if err != nil {
		return errors.Wrap(err, "Failed to suffix session ID to datagram, it will be dropped")
	}
	msgWithIDAndType, err := SuffixType(msgWithID, DatagramTypeUDP)
	if err != nil {
		return errors.Wrap(err, "Failed to suffix datagram type, it will be dropped")
	}
	if err := dm.session.SendDatagram(msgWithIDAndType); err != nil {
		return errors.Wrap(err, "Failed to send datagram back to edge")
	}
	return nil
}

// SendPacket sends a packet with datagram version in the suffix. If ctx is a TracedContext, it adds the tracing
// context between payload and datagram version.
// The other end of the QUIC connection can demultiplex by parsing the payload as IP and look at the source and destination.
func (dm *DatagramMuxerV2) SendPacket(pk Packet) error {
	payloadWithMetadata, err := suffixMetadata(pk.Payload(), pk.Metadata())
	if err != nil {
		return err

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Read the wrapped SuffixSessionID cause to identify which component (ID vs payload) failed.
  2. Shrink the origin UDP payload to leave headroom below the MTU for the ID and type suffixes.
  3. Restart the UDP session / cloudflared to re-establish clean session state.
  4. Verify cloudflared and edge support the same datagram v2 protocol; try --protocol quic vs auto to pin behavior.
Defensive patterns

Strategy: validation

Validate before calling

// enforce a conservative payload cap covering session ID + type suffixes
const maxUDPPayloadV2 = 1200
if len(payload) > maxUDPPayloadV2 {
    return fmt.Errorf("payload %d too large for datagram v2", len(payload))
}

Try / catch

if err := muxer.SendToSession(datagram); err != nil {
    if strings.Contains(err.Error(), "suffix session ID") {
        log.Warn().Str("session", datagram.ID).Msg("dropping datagram: bad session id")
        resetSession(datagram.ID)
    }
    return err
}

Prevention

When it happens

Trigger: SuffixSessionID(session.ID, session.Payload) errors during a v2-protocol UDP datagram send — malformed or unencodable session ID, or payload/session-ID combination exceeding suffix constraints.

Common situations: Protocol mismatch between cloudflared and edge datagram versions corrupting session metadata; near-MTU UDP payloads; corrupted session state after reconnect.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


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