{"record":{"id":"558b893153b8a198","repo":"grpc/grpc-go","slug":"unknown-header-matcher-type","errorCode":null,"errorMessage":"unknown header matcher type","messagePattern":"unknown header matcher type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/rbac/matchers.go","lineNumber":325,"sourceCode":"\t\tm = internalmatcher.NewHeaderRegexMatcher(headerMatcherConfig.Name, regex, headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_RangeMatch:\n\t\tm = internalmatcher.NewHeaderRangeMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetRangeMatch().Start, headerMatcherConfig.GetRangeMatch().End, headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_PresentMatch:\n\t\tm = internalmatcher.NewHeaderPresentMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetPresentMatch(), headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_PrefixMatch:\n\t\tm = internalmatcher.NewHeaderPrefixMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetPrefixMatch(), headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_SuffixMatch:\n\t\tm = internalmatcher.NewHeaderSuffixMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetSuffixMatch(), headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_ContainsMatch:\n\t\tm = internalmatcher.NewHeaderContainsMatcher(headerMatcherConfig.Name, headerMatcherConfig.GetContainsMatch(), headerMatcherConfig.InvertMatch)\n\tcase *v3route_componentspb.HeaderMatcher_StringMatch:\n\t\tsm, err := internalmatcher.StringMatcherFromProto(headerMatcherConfig.GetStringMatch())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid string matcher %+v: %v\", headerMatcherConfig.GetStringMatch(), err)\n\t\t}\n\t\tm = internalmatcher.NewHeaderStringMatcher(headerMatcherConfig.Name, sm, headerMatcherConfig.InvertMatch)\n\tdefault:\n\t\treturn nil, errors.New(\"unknown header matcher type\")\n\t}\n\treturn &headerMatcher{matcher: m}, nil\n}\n\nfunc (hm *headerMatcher) match(data *rpcData) bool {\n\treturn hm.matcher.Match(data.md)\n}\n\n// urlPathMatcher matches on the URL Path of the incoming RPC. In gRPC, this\n// logically maps to the full method name the RPC is calling on the server side.\n// urlPathMatcher implements the matcher interface.\ntype urlPathMatcher struct {\n\tstringMatcher internalmatcher.StringMatcher\n}\n\nfunc newURLPathMatcher(pathMatcher *v3matcherpb.PathMatcher) (*urlPathMatcher, error) {\n\tstringMatcher, err := internalmatcher.StringMatcherFromProto(pathMatcher.GetPath())\n\tif err != nil {","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/rbac/matchers.go#L307-L343","documentation":"`newHeaderMatcher` (internal/xds/rbac/matchers.go:297) switches over the `HeaderMatchSpecifier` oneof of an Envoy HeaderMatcher proto. It handles exact, safe_regex, range, present, prefix, suffix, contains, and string_match variants. The default branch at line 324-325 returns this error when the oneof is unset or holds a variant unknown to gRPC.","triggerScenarios":"Triggered when an RBAC policy (or any xDS resource using HeaderMatcher) contains a header matcher whose `HeaderMatchSpecifier` is either nil (no variant selected) or a newer Envoy variant that gRPC has not implemented. The error is returned during RBAC chain-engine construction, which NACKs the resource.","commonSituations":"A control-plane/Envoy version that emits a header matcher type gRPC does not yet support; a malformed header matcher with no variant set (default-constructed proto); using Envoy-specific extensions in a policy delivered to gRPC; version skew between Envoy proto definitions and the gRPC-vendored ones.","solutions":["Inspect the offending HeaderMatcher proto in the xDS response to identify which (or whether) a match variant is set.","Replace the unsupported/empty header matcher with one of the supported variants (exact, prefix, suffix, contains, present, range, safe_regex, string_match).","If a genuinely new Envoy matcher type is required, check for a newer grpc-go release that supports it; otherwise exclude that policy from gRPC-targeted configs.","Ensure the header matcher is fully populated (the oneof is not left unset) in the control-plane-generated config."],"exampleFix":"// before (HeaderMatcher with no variant / unsupported variant)\nhm := &route_componentspb.HeaderMatcher{Name: \"x-foo\"} // HeaderMatchSpecifier == nil\nm, err := newHeaderMatcher(hm) // err: unknown header matcher type\n\n// after\nhm := &route_componentspb.HeaderMatcher{\n    Name: \"x-foo\",\n    HeaderMatchSpecifier: &route_componentspb.HeaderMatcher_ExactMatch{ExactMatch: \"bar\"},\n}\nm, err := newHeaderMatcher(hm)","handlingStrategy":"type-guard","validationCode":"// Validate a HeaderMatcher proto before it reaches newHeaderMatcher.\nfunc validateHeaderMatcher(hm *route_componentspb.HeaderMatcher) error {\n    if hm == nil || hm.HeaderMatchSpecifier == nil {\n        return fmt.Errorf(\"header matcher %q has no match variant set\", hm.GetName())\n    }\n    switch hm.HeaderMatchSpecifier.(type) {\n    case *route_componentspb.HeaderMatcher_ExactMatch,\n        *route_componentspb.HeaderMatcher_SafeRegexMatch,\n        *route_componentspb.HeaderMatcher_RangeMatch,\n        *route_componentspb.HeaderMatcher_PresentMatch,\n        *route_componentspb.HeaderMatcher_PrefixMatch,\n        *route_componentspb.HeaderMatcher_SuffixMatch,\n        *route_componentspb.HeaderMatcher_ContainsMatch,\n        *route_componentspb.HeaderMatcher_StringMatch:\n        return nil\n    default:\n        return fmt.Errorf(\"header matcher %q uses an unsupported type %T\", hm.GetName(), hm.HeaderMatchSpecifier)\n    }\n}","typeGuard":"// Type-switch helper to confirm a HeaderMatcher variant is one gRPC understands.\nfunc isSupportedHeaderMatcher(hm *route_componentspb.HeaderMatcher) bool {\n    switch hm.HeaderMatchSpecifier.(type) {\n    case *route_componentspb.HeaderMatcher_ExactMatch,\n        *route_componentspb.HeaderMatcher_SafeRegexMatch,\n        *route_componentspb.HeaderMatcher_RangeMatch,\n        *route_componentspb.HeaderMatcher_PresentMatch,\n        *route_componentspb.HeaderMatcher_PrefixMatch,\n        *route_componentspb.HeaderMatcher_SuffixMatch,\n        *route_componentspb.HeaderMatcher_ContainsMatch,\n        *route_componentspb.HeaderMatcher_StringMatch:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Always set a concrete HeaderMatchSpecifier variant when authoring RBAC/route policies.","Add a CI linter that rejects HeaderMatcher blocks with no variant or unknown variants for gRPC consumers.","Track the gRPC-supported Envoy matcher set and pin control-plane versions that emit only those variants."],"tags":["grpc","xds","rbac","matcher","header","validation","version-skew"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}