grpc/grpc-go · error
external processor unexpectedly sent response body when…
Error message
external processor unexpectedly sent response body when response body processing is disabled
What it means
Raised by recvFromProcServerLoop (ext_proc.go:1438) when the ext_proc server sends a response_body response but responseBodyMode is modeSkip (NONE). This is a protocol violation; failProcStream fails the RPC with codes.Internal unless failure_mode_allow bypasses ext_proc.
Solutions
- Ensure the server only returns response_body when ProtocolConfiguration.response_body_mode == GRPC.
- Set response_body_mode to GRPC in the xDS config if you actually want response body mutation.
- Enable failure_mode_allow so the dataplane RPC continues without ext_proc on this violation.
- Fix any shared handler template that unconditionally emits response body mutations.
Example fix
// before: server emits response body even though client mode is NONE
return &procpb.ProcessingResponse{Response: &procpb.ProcessingResponse_ResponseBody{...}}, nil
// after: gate response body output on the negotiated mode
if protocolCfg.GetResponseBodyMode() == procpb.BodySendMode_GRPC {
return &procpb.ProcessingResponse{Response: &procpb.ProcessingResponse_ResponseBody{...}}, nil
} Defensive patterns
Strategy: fallback
Validate before calling
// On the ext_proc SERVER: only emit response_body when the client negotiated GRPC.
func shouldEmitResponseBody(protocolCfg *procpb.ProtocolConfiguration) bool {
return protocolCfg.GetResponseBodyMode() == procpb.BodySendMode_GRPC
} Try / catch
filter.failure_mode_allow = true
if st, ok := status.FromError(err); ok && st.Code() == codes.Internal &&
strings.Contains(st.Message(), "unexpectedly sent response body") {
// server violated the negotiated response body mode
} Prevention
- Gate server response_body output on ProtocolConfiguration.response_body_mode == GRPC.
- Avoid shared handler templates that always emit response body mutations.
- Use failure_mode_allow to prevent the dataplane RPC from failing on a mode mismatch.
- Test the server against a NONE response body config.
When it happens
Trigger: Triggered when processing_mode.response_body_mode is NONE/SKIP but the server returns a ProcessingResponse with response_body set (ext_proc.go:1436).
Common situations: Server assumes response body processing is on while xDS configured NONE, a generic handler always mutating response bodies, or version drift between server expectations and the advertised ProtocolConfiguration.
Related errors
- external processor sent response body after response…
- external processor sent response body before sending…
- external processor unexpectedly sent request body when…
- external processor unexpectedly sent response headers when…
- external processor unexpectedly sent response trailers when…
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/c18eff3169098505.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/httpfilter/extproc/ext_proc.go:1438
switch {
case resp.GetRequestBody() != nil:
if cs.config.processingModes.requestBodyMode == modeSkip {
cs.failProcStream(fmt.Errorf("external processor unexpectedly sent request body when request body processing is disabled"))
return
}
streamedResp, ok := cs.validateBodyResponse(resp.GetRequestBody())
if !ok {
return
}
if streamedResp.GetEndOfStream() {
cs.discardRequests.Store(true)
}
cs.mutatedReqBuffer.Put(streamedResp)
case resp.GetResponseBody() != nil:
if cs.config.processingModes.responseBodyMode == modeSkip {
cs.failProcStream(fmt.Errorf("external processor unexpectedly sent response body when response body processing is disabled"))
return
}
// If response headers have been sent and mutated response headers have
// not been received before receiving the response body message, fail the
// RPC.
if cs.config.processingModes.responseHeaderMode == modeSend && !cs.responseHeadersReady.HasFired() {
cs.failProcStream(fmt.Errorf("external processor sent response body before sending response headers"))
return
}
// If mutated response trailers have been received before receiving the
// response body message, fail the RPC.
if cs.config.processingModes.responseTrailerMode == modeSend && cs.responseTrailerReady.HasFired() {
cs.failProcStream(fmt.Errorf("external processor sent response body after response trailers were already processed"))
return
}
View on GitHub (pinned to 0c51461d27)