grpc/grpc-go · error
external processor returned invalid body mutation in body re
Error message
external processor returned invalid body mutation in body response
What it means
validateBodyResponse extracts the streamed body from the BodyMutation in the body response (ext_proc.go:1361). If BodyMutation or its StreamedResponse field is nil, the filter has no valid chunk to apply and fails the proc stream.
Source
Thrown at internal/xds/httpfilter/extproc/ext_proc.go:1363
if err = cs.applyMutations(trailer.GetHeaderMutation(), cs.responseTrailers); err != nil {
cs.failProcStream(err)
return
}
// Signal that the response trailer is modified and ready to be sent to
// the client.
cs.fireResponseTrailerReady()
}
}
}
func (cs *clientStream) validateBodyResponse(bodyResp *v3procservicepb.BodyResponse) (*v3procservicepb.StreamedBodyResponse, bool) {
if status := bodyResp.GetResponse().GetStatus(); status != v3procservicepb.CommonResponse_CONTINUE {
cs.failProcStream(fmt.Errorf("external processor returned unexpected status %v for body response, expected %v", status, v3procservicepb.CommonResponse_CONTINUE))
return nil, false
}
streamedResp := bodyResp.GetResponse().GetBodyMutation().GetStreamedResponse()
if streamedResp == nil {
cs.failProcStream(fmt.Errorf("external processor returned invalid body mutation in body response"))
return nil, false
}
if streamedResp.GetGrpcMessageCompressed() {
cs.failProcStream(fmt.Errorf("external processor returned compressed grpc message which is not supported"))
return nil, false
}
return streamedResp, true
}
func (cs *clientStream) applyMutations(mutation *v3procservicepb.HeaderMutation, md metadata.MD) error {
if mutation == nil {
return nil
}
if err := cs.config.mutationRules.ApplyAdditions(mutation.GetSetHeaders(), md); err != nil {
return err
}
return cs.config.mutationRules.ApplyRemovals(mutation.GetRemoveHeaders(), md)
}View on GitHub (pinned to 03255a9237)
Solutions
- On the extproc server, always populate bodyMutation.streamed_response (a StreamedBodyResponse with the chunk to forward) when sending a body response.
- If the goal is no-op, still echo the received body bytes in StreamedResponse rather than sending an empty mutation.
- Confirm the server's protobuf definitions match go-control-plane's envoy.service.ext_proc.v3.
Example fix
// before: body mutation left empty
resp.Response.BodyMutation = &procservicepb.BodyMutation{}
// after: populate streamed response
resp.Response.BodyMutation = &procservicepb.BodyMutation{
BodyMutation: &procservicepb.BodyMutation_StreamedResponse{
StreamedResponse: &procservicepb.StreamedBodyResponse{Chunk: chunk},
},
} Defensive patterns
Strategy: validation
Validate before calling
// Server side: ensure StreamedResponse is populated before sending
if bodyResp.GetResponse().GetBodyMutation().GetStreamedResponse() == nil {
bodyResp.Response.BodyMutation = &procservicepb.BodyMutation{BodyMutation: &procservicepb.BodyMutation_StreamedResponse{StreamedResponse: &procservicepb.StreamedBodyResponse{Chunk: chunk}}}
} Prevention
- Never send a body response with an empty BodyMutation.
- Unit-test the server's body-response builder to confirm StreamedResponse is set.
- Match the envoy.service.ext_proc.v3 protobuf oneof exactly.
When it happens
Trigger: The extproc server sends a body ProcessingResponse where BodyMutation is absent or does not populate the StreamedResponse oneof (e.g. it left BodyMutation at its zero value or set the wrong oneof).
Common situations: Server intends to pass the body through unchanged but constructs an empty BodyMutation; server uses the deprecated/cleared mutation variant; protobuf field rename/oneof mismatch between server and client.
Related errors
- external processor unexpectedly sent duplicate response trai
- external processor returned unexpected status %v for body re
- external processor returned compressed grpc message which is
- external processor returned an unexpected message type %T, e
- external processor returned unexpected status %v for request
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/6e5660e077e03e0c.
Report an issue: GitHub.