As seen in grpc/grpc#9956:
... it appears Java/Netty is doing the wrong thing. encoder.remoteSettings() is called before writeSettingsAck(). encoder.remoteSettings() calls flowController().initialWindowSize() which results in the flow controller writing pending bytes.
Two immediate changes should probably be made: 1) Send the settings ack immediately before processing the settings frame in the decoder. Any failure in processing would probably result in the connection being closed, so this doesn't seem dangerous. 2) Stop triggering writePendingBytes() in the flow controller and instead wait for the flush() like normal.