{"record":{"id":"390a82d837647671","repo":"grpc/grpc-go","slug":"extauthz-failed-to-unmarshal-config-v","errorCode":null,"errorMessage":"extauthz: failed to unmarshal config: %v","messagePattern":"extauthz: failed to unmarshal config: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/ext_authz/ext_authz.go","lineNumber":99,"sourceCode":"\treturn fraction{numerator: num, denominator: den}, nil\n}\n\n// grpcStatusCode converts an HTTP status code to a gRPC status code.\nfunc grpcStatusCode(httpStatus int32) codes.Code {\n\tif code, ok := transport.HTTPStatusConvTab[int(httpStatus)]; ok {\n\t\treturn code\n\t}\n\treturn codes.Unknown\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(\"extauthz: error parsing config %v: unknown type %T, want *anypb.Any\", cfg, cfg)\n\t}\n\tmsg := new(v3extauthzpb.ExtAuthz)\n\tif err := m.UnmarshalTo(msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"extauthz: failed to unmarshal config: %v\", err)\n\t}\n\n\tif msg.GetGrpcService() == nil {\n\t\treturn nil, fmt.Errorf(\"extauthz: empty grpc_service provided in config %v\", cfg)\n\t}\n\tserver, err := parseGRPCServiceConfig(msg.GetGrpcService())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extauthz: failed to parse grpc_service: %v\", err)\n\t}\n\n\tfilterEnabled, err := parseFilterEnabled(msg.GetFilterEnabled())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar denyAtDisable bool\n\tif denyAtDisableFlag := msg.GetDenyAtDisable(); denyAtDisableFlag != nil {\n\t\tif denyAtDisableFlag.GetDefaultValue() == nil {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/ext_authz/ext_authz.go#L81-L117","documentation":"Raised by the External Authorization HTTP filter's ParseFilterConfig (ext_authz.go:98) when the bytes inside an *anypb.Any cannot be deserialized into the envoy.extensions.filters.http.ext_authz.v3.ExtAuthz protobuf message. The filter refuses to build a configuration from structurally invalid wire-format data, so the xDS resource carrying this filter is rejected (NACKed) and the previously accepted config remains active.","triggerScenarios":"The xDS resolver hands the HTTP filter's typed_config Any to builder.ParseFilterConfig; the type assertion to *anypb.Any succeeds, but m.UnmarshalTo(new(v3extauthzpb.ExtAuthz)) returns a non-nil error. This happens when the Any payload is truncated, corrupt, or was serialized from a different message type than its type_url claims.","commonSituations":"Control plane (Istio, Traffic Director, etc.) generated a malformed ExtAuthz config; a v2-vs-v3 proto version mismatch where the Any actually contains envoy.config.filter.http.ext_authz.v2; go-control-plane library version skew between the management server and the gRPC client; a hand-crafted xDS resource with mismatched type_url and payload.","solutions":["Read the wrapped %v: a protobuf 'invalid wire type'/'unexpected EOF' points to truncated/corrupt bytes, while a field-level error points to an unknown/wrong-typed field from version skew.","Confirm the Any.type_url is exactly 'type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz' and that the payload was serialized from the same v3 ExtAuthz message.","Decode the Any.value (base64) with protoc --decode against the v3 ExtAuthz descriptor to confirm the bytes are a valid ExtAuthz; if it decodes as another message, fix the control-plane template.","Align the go-control-plane (and envoy proto) versions between your control plane and this gRPC client so the field set matches."],"exampleFix":"// before: control plane emits an Any whose payload is NOT a v3 ExtAuthz\n//   type_url: type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz\n//   value: <bytes serialized from a different/older message>\n//\n// after: marshal the real v3 ExtAuthz into the Any\nimport (\n  \"google.golang.org/protobuf/types/known/anypb\"\n  v3extauthzpb \"github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3\"\n)\n\ncfg := &v3extauthzpb.ExtAuthz{\n  Services: &v3extauthzpb.ExtAuthz_GrpcService{ /* ... */ },\n}\nanyCfg, err := anypb.New(cfg) // type_url + payload always agree\nif err != nil { return err }","handlingStrategy":"validation","validationCode":"// Validate an ExtAuthz Any before publishing it to the control plane\n// (mirrors the check at ext_authz.go:97-99).\nfunc validateExtAuthzAny(a *anypb.Any) error {\n    if a == nil || a.TypeUrl != \"type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz\" {\n        return fmt.Errorf(\"wrong/nil type_url for ExtAuthz\")\n    }\n    msg := new(v3extauthzpb.ExtAuthz)\n    if err := a.UnmarshalTo(msg); err != nil {\n        return fmt.Errorf(\"ExtAuthz payload invalid: %w\", err)\n    }\n    return nil\n}","typeGuard":"// Narrow to *anypb.Any before parsing (ext_authz.go:93).\nfunc asAny(m proto.Message) (*anypb.Any, bool) {\n    a, ok := m.(*anypb.Any)\n    return a, ok\n}","tryCatchPattern":null,"preventionTips":["Always build typed filter configs with anypb.New so the type_url and payload can never disagree.","Keep the go-control-plane (envoy proto) version on your control plane aligned with the gRPC client build.","In CI, decode every xDS resource's Any.value with protoc against the declared descriptor before publishing."],"tags":["grpc","xds","protobuf","config","ext-authz"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}