{"record":{"id":"6de6bbfff7240dff","repo":"grpc/grpc-go","slug":"external-processor-returned-compressed-grpc-messag","errorCode":null,"errorMessage":"external processor returned compressed grpc message which is not supported","messagePattern":"external processor returned compressed grpc message which is not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":1533,"sourceCode":"\t\t\t// Signal that the response trailer is modified and ready to be sent to\n\t\t\t// the client.\n\t\t\tcs.fireResponseTrailerReady()\n\t\t}\n\t}\n}\n\nfunc (cs *clientStream) validateBodyResponse(bodyResp *v3procservicepb.BodyResponse) (*v3procservicepb.StreamedBodyResponse, bool) {\n\tif status := bodyResp.GetResponse().GetStatus(); status != v3procservicepb.CommonResponse_CONTINUE {\n\t\tcs.failProcStream(fmt.Errorf(\"external processor returned unexpected status %v for body response, expected %v\", status, v3procservicepb.CommonResponse_CONTINUE))\n\t\treturn nil, false\n\t}\n\tstreamedResp := bodyResp.GetResponse().GetBodyMutation().GetStreamedResponse()\n\tif streamedResp == nil {\n\t\tcs.failProcStream(fmt.Errorf(\"external processor returned invalid body mutation in body response\"))\n\t\treturn nil, false\n\t}\n\tif streamedResp.GetGrpcMessageCompressed() {\n\t\tcs.failProcStream(fmt.Errorf(\"external processor returned compressed grpc message which is not supported\"))\n\t\treturn nil, false\n\t}\n\treturn streamedResp, true\n}\n\nfunc (cs *clientStream) applyMutations(mutation *v3procservicepb.HeaderMutation, md metadata.MD) error {\n\tif mutation == nil {\n\t\treturn nil\n\t}\n\tif err := cs.config.mutationRules.ApplyAdditions(mutation.GetSetHeaders(), md); err != nil {\n\t\treturn err\n\t}\n\treturn cs.config.mutationRules.ApplyRemovals(mutation.GetRemoveHeaders(), md)\n}\n\n// closeProcSend gracefully half-closes the external processor stream across the\n// background send goroutine by pushing a nil sentinel onto procSendCh.\nfunc (cs *clientStream) closeProcSend() {","sourceCodeStart":1515,"sourceCodeEnd":1551,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L1515-L1551","documentation":"The extproc filter validates body responses from an external gRPC processor. In validateBodyResponse (ext_proc.go:1532), if the streamed body mutation carries GrpcMessageCompressed == true, grpc-go rejects it: the client filter does not implement gRPC-message-level decompression for streamed body responses. The stream is then torn down (or bypassed) via failProcStream.","triggerScenarios":"The external processor returns a ProcessingResponse whose BodyResponse.BodyMutation.StreamedResponse has GrpcMessageCompressed set true. Triggered on the body phase of request or response when the server applies message compression to that streamed mutation.","commonSituations":"External processor server built on a framework that auto-compresses large gRPC messages, or a server-side grpc.UseCompressor(\"gzip\") / compression interceptor applied to the extproc service. Operator enabled compression globally without excluding the extproc service.","solutions":["Disable gRPC message compression on the external processor server for the extproc service (do not call grpc.UseCompressor, or register the service with a none-compression server option).","Audit and remove any compression interceptors on the server that set GrpcMessageCompressed on streamed body responses.","If compression is required for transport, switch the body mutation to a non-streamed form or move the data into a header the filter can carry uncompressed."],"exampleFix":"// before (server side)\ngrpc.NewServer(grpc.UnaryInterceptor(compressInterceptor)) // compresses everything including extproc\n\n// after\ngrpc.NewServer() // extproc service sends uncompressed streamed responses","handlingStrategy":"validation","validationCode":"// Server-side: before sending a streamed body response, ensure the flag is clear\nresp := &procpb.ProcessingResponse{Response: &procpb.ProcessingResponse_ResponseBody{ResponseBody: &procpb.BodyResponse{Response: &procpb.CommonResponse{BodyMutation: &procpb.BodyMutation{Mutation: &procpb.BodyMutation_StreamedResponse{StreamedResponse: &procpb.StreamedBodyResponse{Body: chunk, GrpcMessageCompressed: false}}}}}}}\n_ = resp","typeGuard":null,"tryCatchPattern":"// Client-side: the filter fails the stream with codes.Internal wrapping this message.\n// Catch the RPC error and surface it; if failureModeAllow is true the stream is bypassed.\nstream, err := client.SomeMethod(ctx)\nif err != nil {\n    if st, ok := status.FromError(err); ok && st.Code() == codes.Internal && strings.Contains(st.Message(), \"compressed grpc message\") {\n        // external processor misbehaved; retry without extproc or alert the server owner\n    }\n}","preventionTips":["Do not register compression interceptors on the extproc gRPC server.","Audit grpc.UseCompressor usage in the external processor binary.","Add a server-side unit test asserting GrpcMessageCompressed is false on streamed body responses."],"tags":["extproc","grpc","compression","xds","external-processor"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}