Summary
Stream.ReadMessageHeader is intended to return io.ErrUnexpectedEOF when EOF occurs after only part of the 5-byte gRPC message header has been read. When the partial bytes and EOF arrive from separate recv buffer messages, the final read can return n == 0, io.EOF, so the method returns clean EOF even though earlier iterations already read part of the header.
Why this matters
The error returned by ReadMessageHeader tells callers whether the stream ended cleanly or whether a gRPC message header was truncated. Returning io.EOF after partial header progress hides the fact that malformed or truncated message data was observed.
This makes truncated message-header handling less precise and can make debugging or higher-level error handling harder.
Environment
gRPC version: current master at d74861eb
Go version: go version go1.25.1 X:nodwarf5 linux/amd64
OS: Linux claude 6.16.5-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 04 Sep 2025 23:18:13 +0000 x86_64 GNU/Linux
Trigger
Read a gRPC message header where some bytes of the 5-byte header arrive first, and EOF arrives later as a separate recv buffer message.
Expected behavior
Any EOF after partial header progress should be reported as io.ErrUnexpectedEOF.
Actual behavior
Partial header data followed by EOF can be reported as io.EOF.
Proposed fix
PR #9204 tracks cumulative bytes read while filling a gRPC message header. If EOF occurs after any partial progress, it returns io.ErrUnexpectedEOF even when the final read call itself returned zero bytes. The PR includes a regression test that splits a partial header and EOF across separate recv buffer messages.
Summary
Stream.ReadMessageHeaderis intended to returnio.ErrUnexpectedEOFwhen EOF occurs after only part of the 5-byte gRPC message header has been read. When the partial bytes and EOF arrive from separate recv buffer messages, the final read can returnn == 0, io.EOF, so the method returns clean EOF even though earlier iterations already read part of the header.Why this matters
The error returned by
ReadMessageHeadertells callers whether the stream ended cleanly or whether a gRPC message header was truncated. Returningio.EOFafter partial header progress hides the fact that malformed or truncated message data was observed.This makes truncated message-header handling less precise and can make debugging or higher-level error handling harder.
Environment
gRPC version: current master at
d74861ebGo version:
go version go1.25.1 X:nodwarf5 linux/amd64OS:
Linux claude 6.16.5-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 04 Sep 2025 23:18:13 +0000 x86_64 GNU/LinuxTrigger
Read a gRPC message header where some bytes of the 5-byte header arrive first, and EOF arrives later as a separate recv buffer message.
Expected behavior
Any EOF after partial header progress should be reported as
io.ErrUnexpectedEOF.Actual behavior
Partial header data followed by EOF can be reported as
io.EOF.Proposed fix
PR #9204 tracks cumulative bytes read while filling a gRPC message header. If EOF occurs after any partial progress, it returns
io.ErrUnexpectedEOFeven when the final read call itself returned zero bytes. The PR includes a regression test that splits a partial header and EOF across separate recv buffer messages.