{"record":{"id":"aa37933597a2d32e","repo":"grpc/grpc-go","slug":"extproc-error-parsing-config-v-unknown-type-t","errorCode":null,"errorMessage":"extproc: error parsing config %v: unknown type %T, want *anypb.Any","messagePattern":"extproc: error parsing config (.+?): unknown type %T, want \\*anypb\\.Any","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":112,"sourceCode":"// 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\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)","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/extproc/ext_proc.go#L94-L130","documentation":"Raised by the ext_proc builder's ParseFilterConfig (ext_proc.go:112) when the message handed in is not an *anypb.Any. Like error 364 for the base (not override) config: the builder contract (httpfilter.go:60) expects filter configs wrapped in *anypb.Any, so a non-Any indicates the xDS decoder supplied the wrong concrete proto type for an ExternalProcessor config.","triggerScenarios":"The xDS resolver calls builder.ParseFilterConfig(cfg) where the type assertion cfg.(*anypb.Any) at ext_proc.go:110 fails — an internal resolver/builder contract violation rather than a direct end-user config mistake.","commonSituations":"A resolver change that passes a raw typed struct instead of the wrapping Any; a test calling ParseFilterConfig with the bare ExternalProcessor proto; resolver/filter version skew.","solutions":["If invoking ParseFilterConfig directly, wrap the message with anypb.New first.","In production, treat this as a resolver/builder version mismatch and update gRPC-Go so both sides agree on the *anypb.Any contract.","Ensure the HTTP filter typed_config uses the ExternalProcessor type URL so the resolver keeps it wrapped."],"exampleFix":"// before (direct call): passing the raw ExternalProcessor proto\n//   fc, err := b.ParseFilterConfig(extProc)\n//\n// after: wrap in *anypb.Any\nanyCfg, err := anypb.New(extProc)\nif err != nil { return err }\nfc, err := b.ParseFilterConfig(anyCfg)","handlingStrategy":"type-guard","validationCode":"// Guarantee the config is *anypb.Any before parsing (ext_proc.go:110-112).\nfunc ensureAny(m proto.Message) (*anypb.Any, error) {\n    if a, ok := m.(*anypb.Any); ok {\n        return a, nil\n    }\n    return anypb.New(m)\n}","typeGuard":"func isAnyConfig(m proto.Message) (*anypb.Any, bool) {\n    a, ok := m.(*anypb.Any)\n    return a, ok\n}","tryCatchPattern":null,"preventionTips":["Always pass *anypb.Any into ParseFilterConfig, never the bare ExternalProcessor proto.","Keep resolver and filter builder on the same gRPC-Go version.","In tests/tools, wrap configs with anypb.New."],"tags":["grpc","xds","config","ext-proc","type-assertion"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}