grpc/grpc-go · error

received %d-bytes data exceeding the limit %d bytes

Error message

received %d-bytes data exceeding the limit %d bytes

What it means

This error occurs in inFlow.onData when the total received data (pendingData + pendingUpdate) exceeds the flow control limit plus any delta adjustment. It represents an HTTP/2 flow control violation: the peer sent more data than the receiver's advertised window allows. The stream is then closed with RST_STREAM (FLOW_CONTROL).

Source

Thrown at internal/transport/flowcontrol.go:182

			// estUntransmittedData and estSenderQuota. This will be helpful in case the message
			// is padded; We will fallback on the current available window(at least a 1/4th of the limit).
			f.delta = n
		}
		return f.delta
	}
	return 0
}

// onData is invoked when some data frame is received. It updates pendingData.
func (f *inFlow) onData(n uint32) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	f.pendingData += n
	if f.pendingData+f.pendingUpdate > f.limit+f.delta {
		limit := f.limit
		rcvd := f.pendingData + f.pendingUpdate
		return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", rcvd, limit)
	}
	return nil
}

// onRead is invoked when the application reads the data. It returns the window size
// to be sent to the peer.
func (f *inFlow) onRead(n uint32) uint32 {
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.pendingData == 0 {
		return 0
	}
	f.pendingData -= n
	if n > f.delta {
		n -= f.delta
		f.delta = 0
	} else {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Verify the client is a compliant gRPC/HTTP2 implementation that respects flow control windows.
  2. If streaming large messages, ensure the receiving side reads data promptly to avoid window exhaustion.
  3. Check for version mismatches between client and server gRPC libraries that might have flow control bugs.
  4. If you control both sides, consider increasing InitialWindowSize via dial/server options for large payloads.

Example fix

// before (broken): receiver doesn't read stream, sender floods data
stream, _ := client.LargeData(ctx)
// ... sender writes 100MB while receiver never calls stream.Recv()

// after (valid): receiver reads promptly to drain the flow control window
for {
    resp, err := stream.Recv()
    if err == io.EOF { break }
    if err != nil { log.Fatal(err) }
    // process resp incrementally
}
Defensive patterns

Strategy: validation

Try / catch

// Server-side: when a stream is closed with FLOW_CONTROL error, the stream
// returns an error to the handler. Check for ResourceExhausted:
if status.Code(err) == codes.ResourceExhausted {
    log.Printf("peer violated flow control: %v", err)
    // the stream is already terminated; no recovery possible
}

Prevention

When it happens

Trigger: A gRPC peer sends a DATA frame that pushes the cumulative unconsumed data past the stream's flow control window. This can happen when the receiver is slow to read and the sender's window accounting is buggy, or when a non-compliant client ignores window limits.

Common situations: Client sends a very large message faster than the server reads it and a buggy client implementation doesn't respect flow control; or mismatched initial window size settings between client and server causing accounting discrepancies; or a malicious/buggy peer intentionally flooding data.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/4c5e4cc700e0db39. Report an issue: GitHub.