{"record":{"id":"294cd0801a466108","repo":"grpc/grpc-go","slug":"extproc-empty-grpc-service-provided-in-config-v","errorCode":null,"errorMessage":"extproc: empty grpc_service provided in config %v","messagePattern":"extproc: empty grpc_service provided in config (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":126,"sourceCode":"\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\n\t}\n\n\tif msg.GetGrpcService() == nil {\n\t\treturn nil, fmt.Errorf(\"extproc: empty grpc_service provided in config %v\", cfg)\n\t}\n\tserver, err := iextproc.ParseGRPCServiceConfig(msg.GetGrpcService())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extproc: failed to parse grpc_service %v\", err)\n\t}\n\n\tmutationRules, err := httpfilter.HeaderMutationRulesFromProto(msg.GetMutationRules())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar allowedHeaders, disallowedHeaders []matcher.StringMatcher\n\tif allowed := msg.GetForwardRules().GetAllowedHeaders(); allowed != nil {\n\t\tallowedHeaders, err = httpfilter.ConvertStringMatchers(allowed.GetPatterns())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L108-L144","documentation":"Returned by ParseFilterConfig when the decoded ExternalProcessor message has a nil grpc_service field. The grpc_service tells the client where the external processor server lives (target URI, credentials); without it the filter cannot connect to a processor. Hit at ext_proc.go:125.","triggerScenarios":"An xDS ExternalProcessor resource is sent without grpc_service populated. ParseFilterConfig checks msg.GetGrpcService() == nil and rejects the config.","commonSituations":"The grpc_service was templated from a variable that resolved empty; a config author relied on a non-existent default; the field was dropped during a proto refactor.","solutions":["Populate grpc_service with a valid envoy.config.core.v3.GrpcService (at least a target URI).","Use the google_grpc or envoy_grpc variant as appropriate for your environment.","Add schema validation in the control plane requiring grpc_service for ext_proc filters.","Diff the resource against a known-good ext_proc config."],"exampleFix":"# before\n# ExternalProcessor with grpc_service omitted\n# after\ngrpc_service:\n  envoy_grpc:\n    cluster_name: ext-proc-cluster","handlingStrategy":"validation","validationCode":"// control-plane guard\nif cfg.GetGrpcService() == nil {\n  return fmt.Errorf(\"ext_proc config requires grpc_service\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always populate grpc_service with a target and credentials.","Add control-plane schema validation requiring grpc_service.","Confirm the referenced cluster exists in the bootstrap.","Diff against a known-good ext_proc config."],"tags":["grpc","xds","extproc","config","required-field"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}