{"record":{"id":"5d3938a54bea0115","repo":"grpc/grpc-go","slug":"extproc-error-parsing-override-v-unknown-type","errorCode":null,"errorMessage":"extproc: error parsing override %v: unknown type %T, want *anypb.Any","messagePattern":"extproc: error parsing override (.+?): unknown type %T, want \\*anypb\\.Any","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":176,"sourceCode":"\treturn baseConfig{\n\t\tprocessingModes:          processingModesFromProto(msg.GetProcessingMode()),\n\t\trequestAttributes:        msg.GetRequestAttributes(),\n\t\tresponseAttributes:       msg.GetResponseAttributes(),\n\t\tdisableImmediateResponse: msg.GetDisableImmediateResponse(),\n\t\tobservabilityMode:        msg.GetObservabilityMode(),\n\t\tfailureModeAllow:         msg.GetFailureModeAllow(),\n\t\tserver:                   server,\n\t\tmutationRules:            mutationRules,\n\t\tallowedHeaders:           allowedHeaders,\n\t\tdisallowedHeaders:        disallowedHeaders,\n\t\tdeferredCloseTimeout:     deferredCloseTimeout,\n\t}, nil\n}\n\nfunc (builder) ParseFilterConfigOverride(ov proto.Message) (httpfilter.FilterConfig, error) {\n\tm, ok := ov.(*anypb.Any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"extproc: error parsing override %v: unknown type %T, want *anypb.Any\", ov, ov)\n\t}\n\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())","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/extproc/ext_proc.go#L158-L194","documentation":"Raised by ParseFilterConfigOverride when the per-route override proto passed to the extproc filter builder is not a *anypb.Any. The XDS layer is expected to always hand the filter a decoded *anypb.Any; this assertion enforces that contract. Hitting it means the data path feeding filter overrides deviated from the registered type-URL contract.","triggerScenarios":"ParseFilterConfigOverride is called (during LDS/xDS resource decoding) with a proto.Message whose concrete type is not *anypb.Any — e.g. a test invoking the builder directly with a *v3procfilterpb.ExtProcPerRoute instead of wrapping it in an Any, or a non-conformant custom httpfilter plumbing that forwards the unwrapped message.","commonSituations":"Unit/integration tests that call ParseFilterConfigOverride directly without wrapping the override in anypb.New(). A forked or custom xDS client that decodes typed_per_filter_config into the inner message type before handing it to the builder. A filter-registry bug that re-dispatches the wrong concrete type.","solutions":["Wrap the per-route override message in *anypb.Any before passing it to ParseFilterConfigOverride: anypb.New(&v3procfilterpb.ExtProcPerRoute{...}).","If this surfaces from real xDS traffic, verify the LDS route configuration encodes typed_per_filter_config as a typed Struct/Any with @type set to type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute.","Check that no other httpfilter.Register call shadowed extproc's builder, which can corrupt type dispatch."],"exampleFix":"// before\nm := &v3procfilterpb.ExtProcPerRoute{Overrides: &v3procfilterpb.ExtProcPerRoute_Overrides{...}}\ncfg, err := builder{}.ParseFilterConfigOverride(m)\n\n// after\na, _ := anypb.New(&v3procfilterpb.ExtProcPerRoute{Overrides: &v3procfilterpb.ExtProcPerRoute_Overrides{...}})\ncfg, err := builder{}.ParseFilterConfigOverride(a)","handlingStrategy":"type-guard","validationCode":"// The XDS layer should always pass *anypb.Any; guard in code that wraps the builder.\nfunc safeParseOverride(b httpfilter.FilterBuilder, ov proto.Message) (httpfilter.FilterConfig, error) {\n    if _, ok := ov.(*anypb.Any); !ok {\n        return nil, fmt.Errorf(\"override must be *anypb.Any, got %T\", ov)\n    }\n    return b.ParseFilterConfigOverride(ov)\n}","typeGuard":"func isAny(m proto.Message) bool { _, ok := m.(*anypb.Any); return ok }","tryCatchPattern":null,"preventionTips":["Always wrap per-route overrides with anypb.New before invoking ParseFilterConfigOverride in tests.","Keep typed_per_filter_config entries keyed by filter name so the registry dispatches the right builder."],"tags":["extproc","xds","config-parsing","protobuf"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}