{"record":{"id":"efbc9324a71e3b6b","repo":"grpc/grpc-go","slug":"extproc-invalid-response-trailer-mode-v-must-be","errorCode":null,"errorMessage":"extproc: invalid response trailer mode %v: must be %q when response body mode is %q","messagePattern":"extproc: invalid response trailer mode (.+?): must be %q when response body mode is %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":104,"sourceCode":"func (builder) TypeURLs() []string {\n\treturn []string{\n\t\t\"type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor\",\n\t\t\"type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute\",\n\t}\n}\n\n// validateBodyProcessingMode ensures that the body processing mode is either\n// NONE or GRPC. Also ensures that if response body mode is GRPC then response\n// trailer mode must be SEND.\nfunc validateBodyProcessingMode(mode *v3procfilterpb.ProcessingMode) error {\n\tif m := mode.GetRequestBodyMode(); m != v3procfilterpb.ProcessingMode_NONE && m != v3procfilterpb.ProcessingMode_GRPC {\n\t\treturn fmt.Errorf(\"extproc: invalid request body mode %v: want %q or %q\", m, \"NONE\", \"GRPC\")\n\t}\n\tif m := mode.GetResponseBodyMode(); m != v3procfilterpb.ProcessingMode_NONE && m != v3procfilterpb.ProcessingMode_GRPC {\n\t\treturn fmt.Errorf(\"extproc: invalid response body mode %v: want %q or %q\", m, \"NONE\", \"GRPC\")\n\t}\n\tif mode.GetResponseBodyMode() == v3procfilterpb.ProcessingMode_GRPC && mode.GetResponseTrailerMode() != v3procfilterpb.ProcessingMode_SEND {\n\t\treturn fmt.Errorf(\"extproc: invalid response trailer mode %v: must be %q when response body mode is %q\", mode.GetResponseTrailerMode(), \"SEND\", \"GRPC\")\n\t}\n\treturn nil\n}\n\nfunc (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {\n\tm, ok := cfg.(*anypb.Any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"extproc: error parsing config %v: unknown type %T, want *anypb.Any\", cfg, cfg)\n\t}\n\tmsg := new(v3procfilterpb.ExternalProcessor)\n\tif err := m.UnmarshalTo(msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"extproc: failed to unmarshal config %v: %v\", cfg, err)\n\t}\n\tif msg.GetProcessingMode() == nil {\n\t\treturn nil, fmt.Errorf(\"extproc: missing processing_mode in config %v\", cfg)\n\t}\n\tif err := validateBodyProcessingMode(msg.GetProcessingMode()); err != nil {\n\t\treturn nil, err","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L86-L122","documentation":"Returned by validateBodyProcessingMode when response_body_mode is GRPC but response_trailer_mode is not SEND. grpc-go requires that, when it forwards response bodies (which include the gRPC message frames), it also forwards response trailers so the ext_proc server can observe grpc-status/grpc-message. Hit at ext_proc.go:103.","triggerScenarios":"An xDS config sets processing_mode.response_body_mode=GRPC and processing_mode.response_trailer_mode to something other than SEND (or leaves it defaulted in a way that resolves non-SEND). validateBodyProcessingMode returns this error.","commonSituations":"Operator disables trailer forwarding to save a round trip; config partially migrated and the trailer mode field was reset; misunderstanding that GRPC body mode implies trailer forwarding.","solutions":["Set processing_mode.response_trailer_mode to SEND whenever response_body_mode is GRPC.","If you do not want trailer forwarding, switch response_body_mode to NONE instead.","Add a control-plane validation rule: response_body_mode==GRPC implies response_trailer_mode==SEND.","Test the config against a grpc-go client before rolling out."],"exampleFix":"# before (inconsistent)\nprocessing_mode:\n  response_body_mode: GRPC\n  response_trailer_mode: SKIP\n# after\nprocessing_mode:\n  response_body_mode: GRPC\n  response_trailer_mode: SEND","handlingStrategy":"validation","validationCode":"// control-plane guard\nif cfg.ProcessingMode.GetResponseBodyMode() == v3extproc.ProcessingMode_GRPC &&\n   cfg.ProcessingMode.GetResponseTrailerMode() != v3extproc.ProcessingMode_SEND {\n  return fmt.Errorf(\"response_trailer_mode must be SEND when response_body_mode is GRPC\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add a control-plane rule: response_body_mode==GRPC implies response_trailer_mode==SEND.","If trailers are not wanted, use response_body_mode=NONE.","Validate configs with a grpc-go client before rollout.","Document the implication in the schema."],"tags":["grpc","xds","extproc","config","processing-mode"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}