{"record":{"id":"69ff11dd68512ea6","repo":"grpc/grpc-go","slug":"fault-error-parsing-config-v-unknown-type-t","errorCode":null,"errorMessage":"fault: error parsing config %v: unknown type %T","messagePattern":"fault: error parsing config (.+?): unknown type %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/fault/fault.go","lineNumber":87,"sourceCode":"}\n\ntype config struct {\n\thttpfilter.FilterConfig\n\tconfig *fpb.HTTPFault\n}\n\nfunc (builder) TypeURLs() []string {\n\treturn []string{\"type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault\"}\n}\n\n// Parsing is the same for the base config and the override config.\nfunc parseConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"fault: nil configuration message provided\")\n\t}\n\tm, ok := cfg.(*anypb.Any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"fault: error parsing config %v: unknown type %T\", cfg, cfg)\n\t}\n\tmsg := new(fpb.HTTPFault)\n\tif err := m.UnmarshalTo(msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"fault: error parsing config %v: %v\", cfg, err)\n\t}\n\treturn config{config: msg}, nil\n}\n\nfunc (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {\n\treturn parseConfig(cfg)\n}\n\nfunc (builder) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) {\n\treturn parseConfig(override)\n}\n\nfunc (builder) IsTerminal() bool {\n\treturn false","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/fault/fault.go#L69-L105","documentation":"parseConfig expects the incoming proto.Message to be an *anypb.Any (fault.go:85). Any other concrete type indicates the xDS decoding pipeline passed the wrong message type to the fault builder, which is a programmer/decoder contract violation.","triggerScenarios":"ParseFilterConfig receives a proto.Message that is not *anypb.Any (e.g. the already-unwrapped *fpb.HTTPFault or a raw struct message).","commonSituations":"A custom xdsclient/resource-decoder that pre-unwraps the Any before handing it to the filter builder; test harness passing the concrete type; type-url routing mismatch causing the wrong builder to handle the message.","solutions":["Always pass an *anypb.Any whose TypeURL is type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault.","Fix the resource decoder so it does not pre-unmarshal the filter config before the builder sees it.","Confirm the TypeURLs() of the fault builder match the resource type being routed to it."],"exampleFix":"// before: passing the concrete HTTPFault directly\nfc, err := faultBuilder.ParseFilterConfig(&fpb.HTTPFault{})\n\n// after: wrap in *anypb.Any\nanyMsg, _ := anypb.New(&fpb.HTTPFault{})\nfc, err := faultBuilder.ParseFilterConfig(anyMsg)","handlingStrategy":"type-guard","validationCode":"if _, ok := cfg.(*anypb.Any); !ok {\n    return nil, fmt.Errorf(\"expected *anypb.Any, got %T\", cfg)\n}\nfc, err := faultBuilder.ParseFilterConfig(cfg)","typeGuard":"func isAnyMsg(m proto.Message) bool {\n    _, ok := m.(*anypb.Any)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Always hand *anypb.Any to filter builders, not pre-unwrapped messages.","Keep the decoder and builder types aligned via shared TypeURL constants.","Add a type assertion in the decoder before dispatching to builders."],"tags":["fault-injection","grpc","xds","config","type-mismatch","go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}