txthinking/brook · error

when write to client, quic max datagram size is 1197

Error message

when write to client, quic max datagram size is 1197

What it means

The QUIC server enforces the same 1197-byte ceiling when sending datagrams back to the client. Inside the write-back callback of UDPServerConnFactory.Handle, any response payload longer than 1197 bytes cannot be sent as a QUIC datagram (header + AEAD overhead would exceed the QUIC datagram limit), so the server logs and returns this error to the handler instead of sending a truncated packet.

Source

Thrown at quicserver.go:187

							RAddr: &net.TCPAddr{
								IP:   c.RemoteAddr().(*net.UDPAddr).IP,
								Port: c.RemoteAddr().(*net.UDPAddr).Port,
								Zone: c.RemoteAddr().(*net.UDPAddr).Zone,
							},
						})
					}
				}(c)
				if c.ConnectionState().SupportsDatagrams {
					go func(c quic.Connection) {
						defer c.CloseWithError(0, "defer")
						for {
							b, err := c.ReceiveDatagram(context.Background())
							if err != nil {
								return
							}
							conn, dstb, err := s.UDPServerConnFactory.Handle(c.RemoteAddr().(*net.UDPAddr), b, s.Password, func(b []byte) (int, error) {
								if len(b) > 1197 {
									err := errors.New("when write to client, quic max datagram size is 1197")
									Log(Error{"from": c.RemoteAddr().String(), "error": err.Error()})
									return 0, err
								}
								if err := c.SendDatagram(b); err != nil {
									return 0, err
								}
								return len(b), nil
							}, s.UDPTimeout)
							if err != nil {
								Log(Error{"from": c.RemoteAddr().String(), "error": err.Error()})
								continue
							}
							if conn == nil {
								continue
							}
							go func() {
								defer conn.Close()
								var ss Exchanger

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Limit the request so the response fits: for DNS, query with smaller EDNS0 buffer sizes or avoid ANY/DNSSEC-heavy queries so replies stay under 1197 bytes.
  2. Route large UDP exchanges over TCP (DNS over TCP) or use a stream-based proxy transport instead of QUIC datagrams.
  3. On the client, handle the failed response by retrying over a TCP-backed path when the server reports this error.

Example fix

// before
resp, _ := resolver.Exchange(bigQuery, udpViaQuic) // server rejects >1197-byte reply

// after
if resp.Len() > 1197 {
    resp, err = resolver.ExchangeViaTCP(bigQuery) // stream path has no datagram cap
}
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side guard before sending a query whose reply may be large
if requestKind == dnsKIND_ANY || ednsBufferSize > 1232 {
    useTCPPath = true
}

Try / catch

// server write-back closure returns the error to the factory handler
if len(b) > 1197 {
    return 0, errTooLarge // caller should retry over TCP/stream path
}

Prevention

When it happens

Trigger: A remote UDP peer (e.g. a DNS server) returns a response larger than 1197 bytes; the server's write-back closure in quicserver.go receives b with len(b) > 1197 and returns the error, aborting the relayed response.

Common situations: Large DNS responses over UDP (big TXT records, DNSSEC-signed answers, ANY queries), or any upstream UDP service that replies with datagrams near the path MTU while the client is connected via QUIC.

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 txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/d745d078686f6147. Report an issue: GitHub.