{"record":{"id":"ff3e15a422b5eeaa","repo":"grpc/grpc-go","slug":"extproc-failed-to-parse-grpc-service-v-ff3e15","errorCode":null,"errorMessage":"extproc: failed to parse grpc_service: %v","messagePattern":"extproc: failed to parse grpc_service: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":196,"sourceCode":"\tmsg := new(v3procfilterpb.ExtProcPerRoute)\n\tif err := m.UnmarshalTo(msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"extproc: failed to unmarshal override %v: %v\", ov, err)\n\t}\n\toverride := msg.GetOverrides()\n\n\tvar processingModesOpt optional.Optional[processingModes]\n\tif pm := override.GetProcessingMode(); pm != nil {\n\t\tif err := validateBodyProcessingMode(pm); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tprocessingModesOpt = optional.New(processingModesFromProto(pm))\n\t}\n\n\tvar serverOpt optional.Optional[xdsresource.GRPCServiceConfig]\n\tif override.GetGrpcService() != nil {\n\t\tserver, err := iextproc.ParseGRPCServiceConfig(override.GetGrpcService())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"extproc: failed to parse grpc_service: %v\", err)\n\t\t}\n\t\tserverOpt = optional.New(server)\n\t}\n\n\tvar failureModeAllowOpt optional.Optional[bool]\n\tif override.GetFailureModeAllow() != nil {\n\t\tfailureModeAllowOpt = optional.New(override.GetFailureModeAllow().GetValue())\n\t}\n\n\treturn overrideConfig{\n\t\tserver:             serverOpt,\n\t\tprocessingModes:    processingModesOpt,\n\t\tfailureModeAllow:   failureModeAllowOpt,\n\t\trequestAttributes:  override.GetRequestAttributes(),\n\t\tresponseAttributes: override.GetResponseAttributes(),\n\t}, nil\n}\n","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L178-L214","documentation":"Returned by ParseFilterConfigOverride (ext_proc.go:196) when the override's grpc_service field cannot be parsed by iextproc.ParseGRPCServiceConfig. Only the override path is affected; the route is rejected because the per-route external-processor target is not usable.","triggerScenarios":"Triggered when an ExtProcPerRoute override sets overrides.grpc_service (ext_proc.go:193) and the underlying ParseGRPCServiceConfig returns an error — e.g. a google_grpc payload (Envoy's GoogleGrpc) instead of the supported grpc (EnvoyGrpc), an unsupported credentials type, an empty target, or a malformed authority.","commonSituations":"Configuring a per-route override that points to a different ext_proc server than the base config but using Envoy's google_grpc variant, omitting the target_uri, using a credentials spec the client does not implement, or a control-plane version that emits a grpc_service shape the client cannot consume.","solutions":["Use the envoy.config.core.v3.GrpcService.grpc (EnvoyGrpc) variant with a valid target_uri in the override, not the google_grpc variant.","Ensure target_uri is non-empty and resolvable (e.g. dns:///ext-proc.default.svc:443).","Strip per-route grpc_service overrides you do not need and let the base config supply the server.","Upgrade the client and control plane to a matching revision that supports the credentials/authority fields in use."],"exampleFix":"// before: override uses GoogleGrpc which gRPC-Go ext_proc cannot parse\noverride.GrpcService = &corev3.GrpcService{\n  TargetIdentifier: \"ext-proc:443\",\n}\n\n// after: use EnvoyGrpc with an explicit target\noverride.GrpcService = &corev3.GrpcService{\n  TargetIdentifier: \"envoy_grpc\",\n}\noverride.GrpcService.GetEnvoyGrpc().ClusterName = \"ext_proc_cluster\"","handlingStrategy":"validation","validationCode":"// Validate the override grpc_service is parseable before publishing.\nfunc validateOverrideGrpcService(gs *corev3.GrpcService) error {\n    if gs == nil {\n        return nil // override server is optional\n    }\n    if gs.GetEnvoyGrpc() == nil {\n        return fmt.Errorf(\"override grpc_service must use envoy_grpc; google_grpc is not supported\")\n    }\n    if gs.GetEnvoyGrpc().GetClusterName() == \"\" {\n        return fmt.Errorf(\"override envoy_grpc.cluster_name is empty\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := builder{}.ParseFilterConfigOverride(overrideAny); err != nil {\n    if strings.Contains(err.Error(), \"failed to parse grpc_service\") {\n        // the per-route grpc_service is invalid; drop it and reuse the base server\n    }\n}","preventionTips":["Prefer envoy_grpc (EnvoyGrpc) over google_grpc for ext_proc grpc_service.","Leave the per-route grpc_service unset when you can reuse the base config server.","Keep a unit test that runs ParseFilterConfigOverride on every override template you publish.","Document the supported credentials subset so authors do not send unsupported fields."],"tags":["grpc","xds","extproc","envoy","config","grpc-service"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}