{"record":{"id":"c18eff3169098505","repo":"grpc/grpc-go","slug":"external-processor-unexpectedly-sent-response-body","errorCode":null,"errorMessage":"external processor unexpectedly sent response body when response body processing is disabled","messagePattern":"external processor unexpectedly sent response body when response body processing is disabled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":1272,"sourceCode":"\t\tswitch {\n\t\tcase resp.GetRequestBody() != nil:\n\t\t\tif cs.config.processingModes.requestBodyMode == modeSkip {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor unexpectedly sent request body when request body processing is disabled\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tstreamedResp, ok := cs.validateBodyResponse(resp.GetRequestBody())\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif streamedResp.GetEndOfStream() {\n\t\t\t\tcs.discardRequests.Store(true)\n\t\t\t}\n\t\t\tcs.mutatedReqBuffer.Put(streamedResp)\n\n\t\tcase resp.GetResponseBody() != nil:\n\t\t\tif cs.config.processingModes.responseBodyMode == modeSkip {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor unexpectedly sent response body when response body processing is disabled\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If response headers have been sent and mutated response headers have\n\t\t\t// not been received before receiving the response body message, fail the\n\t\t\t// RPC.\n\t\t\tif cs.config.processingModes.responseHeaderMode == modeSend && !cs.responseHeadersReady.HasFired() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor sent response body before sending response headers\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If mutated response trailers have been received before receiving the\n\t\t\t// response body message, fail the RPC.\n\t\t\tif cs.config.processingModes.responseTrailerMode == modeSend && cs.responseTrailerReady.HasFired() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor sent response body after response trailers were already processed\"))\n\t\t\t\treturn\n\t\t\t}\n","sourceCodeStart":1254,"sourceCodeEnd":1290,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/extproc/ext_proc.go#L1254-L1290","documentation":"Raised in recvFromProcServerLoop when the server's response carries a response_body field but responseBodyMode is modeSkip. The client did not negotiate response-body processing, so a response-body mutation is a protocol violation and the proc stream is failed.","triggerScenarios":"An ext-proc server sends a ProcessingResponse.response_body while processing_mode.response_body_mode is NONE. failProcStream decides teardown (failure_mode_allow off) or bypass (on).","commonSituations":"Server blindly mutates response bodies; client left response_body_mode at the NONE default. Per-route override disabled body mode but the shared server implementation still emits response_body.","solutions":["Set processing_mode.response_body_mode to GRPC if response-body processing is desired.","Otherwise, correct the server so it never sets response_body when the negotiated ProtocolConfiguration has ResponseBodyMode NONE.","Enable failure_mode_allow to bypass the processor on violation while you remediate the server."],"exampleFix":"// before\nprocessing_mode:\n  response_body_mode: NONE   # server returns response_body anyway\n\n// after\nprocessing_mode:\n  response_body_mode: GRPC","handlingStrategy":"validation","validationCode":"// Server-side guard: suppress response_body when mode is NONE.\nfunc maybeResponseBody(mode v3procfilterpb.ProcessingMode_BodySendMode, resp *pb.ProcessingResponse) *pb.ProcessingResponse {\n    if mode == v3procfilterpb.ProcessingMode_NONE && resp.GetResponseBody() != nil {\n        return nil\n    }\n    return resp\n}","typeGuard":null,"tryCatchPattern":"// Client side: failure_mode_allow -> bypass on violation.","preventionTips":["Align response_body_mode with server behavior.","Enable failure_mode_allow during server rollouts."],"tags":["extproc","protocol-violation","processing-mode","response-body","server-bug"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}