Skip to content

fix(web): emit trailers when the response body ends - #2830

Open
emersonian wants to merge 1 commit into
grpc:v0.14.xfrom
emersonian:fix-web-client-buffered-trailers
Open

fix(web): emit trailers when the response body ends#2830
emersonian wants to merge 1 commit into
grpc:v0.14.xfrom
emersonian:fix-web-client-buffered-trailers

Conversation

@emersonian

Copy link
Copy Markdown

Motivation

GrpcWebClientLayer fails every call with "protocol error: missing grpc-status trailer, stream was terminated without a final status" when the server delivers a message frame and the gRPC-Web trailers frame in the same body chunk, the common framing for unary responses (observed against Envoy's grpc-web filter, which flushes the whole response in one chunk).

Solution

The client decode path in GrpcWebCall::poll_frame buffers body bytes and, when data and trailers share a buffer, parses the trailers into self.trailers and returns the data frame first.

On the next poll the buffer is empty, find_trailers reports Done(0), and the stream ended with None without ever emitting the stored trailers. This change takes and emits the stored trailers in the Done(0) arm before ending the stream.

Test coverage

This PR adds a regression test polling a client_response body whose single chunk carries a message frame followed by the trailers frame, asserting the data frame is followed by the trailers rather than end of stream (it fails on the unfixed code with the exact symptom above).

The client decode path in GrpcWebCall::poll_frame buffers body bytes and,
when a message frame and the gRPC-Web trailers frame land in the same
buffer, parses the trailers into self.trailers and returns the data frame
first. On the next poll the buffer is empty, find_trailers reports
Done(0), and the stream ended with None without ever emitting the stored
trailers, so tonic failed every such call with "protocol error: missing
grpc-status trailer", even though the server sent a well-formed response.
This is the common framing for unary responses (observed deterministically
against Envoy's grpc-web filter), where the whole body arrives as one
chunk.

Take and emit the stored trailers in the Done(0) arm before ending the
stream. Adds a regression test that polls a client_response body whose
single chunk carries a message frame followed by the trailers frame, and
asserts the data frame is followed by the trailers rather than end of
stream.
@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 21, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: emersonian / name: Blake Emerson (803349d)

@emersonian
emersonian changed the base branch from master to v0.14.x August 21, 2026 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant