{"record":{"id":"8235308050ca7265","repo":"grpc/grpc-go","slug":"external-processor-unexpectedly-sent-request-body","errorCode":null,"errorMessage":"external processor unexpectedly sent request body when request body processing is disabled","messagePattern":"external processor unexpectedly sent request body when request body processing is disabled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":1257,"sourceCode":"\t\tif err != nil {\n\t\t\tcs.failProcStream(err)\n\t\t\treturn\n\t\t}\n\t\tif resp.GetRequestDrain() {\n\t\t\t// Trigger the drain but continue receiving the drained messages until we\n\t\t\t// get io.EOF.\n\t\t\tcs.triggerBypass()\n\t\t}\n\n\t\tif resp.GetImmediateResponse() != nil {\n\t\t\tcs.handleImmediateResponse(resp.GetImmediateResponse(), newStream, opts)\n\t\t\treturn\n\t\t}\n\n\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","sourceCodeStart":1239,"sourceCodeEnd":1275,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/extproc/ext_proc.go#L1239-L1275","documentation":"Raised in recvFromProcServerLoop when the external processor's response carries a request_body field but the configured requestBodyMode is modeSkip. The client never asked to process request bodies, so a request-body mutation from the server is a protocol violation and the proc stream is failed via failProcStream.","triggerScenarios":"An ext-proc server sends a ProcessingResponse with the request_body oneof set while the filter's processing_mode.request_body_mode is NONE (the default). failProcStream then either tears down the RPC or, with failure_mode_allow, bypasses the processor.","commonSituations":"Server assumes it should echo/mutate request bodies but the LDS processing_mode leaves request_body_mode at NONE. Server implementation copied from an example that does body mutation without checking the negotiated mode. Mismatch between what the server thinks it can do and the mode the client negotiated in ProtocolConfiguration.","solutions":["If you want request-body processing, set processing_mode.request_body_mode to GRPC in the LDS config.","If request-body processing is intentionally off, fix the server to never populate request_body in its responses.","Enable failure_mode_allow so a misbehaving server bypasses instead of failing user RPCs while you fix it."],"exampleFix":"// before: mode off, server sends request_body\nprocessing_mode:\n  request_body_mode: NONE   # server nonetheless returns request_body\n\n// after (option A — enable body processing)\nprocessing_mode:\n  request_body_mode: GRPC\n// after (option B — stop the server from sending request_body)","handlingStrategy":"validation","validationCode":"// Server-side guard: only emit request_body when negotiated mode allows it.\nfunc maybeRequestBody(mode v3procfilterpb.ProcessingMode_BodySendMode, resp *pb.ProcessingResponse) *pb.ProcessingResponse {\n    if mode == v3procfilterpb.ProcessingMode_NONE && resp.GetRequestBody() != nil {\n        return nil // do not send; would trigger client-side error 389\n    }\n    return resp\n}","typeGuard":null,"tryCatchPattern":"// Client side: failure_mode_allow converts violation -> bypass instead of RPC failure.","preventionTips":["Make request_body_mode in LDS match what the server actually sends.","Set failure_mode_allow: true to absorb server misbehavior while remediating."],"tags":["extproc","protocol-violation","processing-mode","request-body","server-bug"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}