grpc/grpc-go · error
rbac: principal header matcher for %v is :scheme or starts w
Error message
rbac: principal header matcher for %v is :scheme or starts with grpc
What it means
Per gRFC A41, an RBAC policy is invalid if any Principal has a header matcher whose name is ':scheme' or starts with 'grpc-' (rbac.go:74). grpc-go controls these headers internally, so matching on them is unsupported and the policy is rejected at config time.
Source
Thrown at internal/xds/httpfilter/rbac/rbac.go:75
// Parsing is the same for the base config and the override config.
func parseConfig(rbacCfg *rpb.RBAC) (httpfilter.FilterConfig, error) {
// All the validation logic described in A41.
for _, policy := range rbacCfg.GetRules().GetPolicies() {
// "Policy.condition and Policy.checked_condition must cause a
// validation failure if present." - A41
if policy.Condition != nil {
return nil, errors.New("rbac: Policy.condition is present")
}
if policy.CheckedCondition != nil {
return nil, errors.New("rbac: policy.CheckedCondition is present")
}
// "It is also a validation failure if Permission or Principal has a
// header matcher for a grpc- prefixed header name or :scheme." - A41
for _, principal := range policy.Principals {
name := principal.GetHeader().GetName()
if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
return nil, fmt.Errorf("rbac: principal header matcher for %v is :scheme or starts with grpc", name)
}
}
for _, permission := range policy.Permissions {
name := permission.GetHeader().GetName()
if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
return nil, fmt.Errorf("rbac: permission header matcher for %v is :scheme or starts with grpc", name)
}
}
}
// "Envoy aliases :authority and Host in its header map implementation, so
// they should be treated equivalent for the RBAC matchers; there must be no
// behavior change depending on which of the two header names is used in the
// RBAC policy." - A41. Loop through config's principals and policies, change
// any header matcher with value "host" to :authority", as that is what
// grpc-go shifts both headers to in transport layer.
for _, policy := range rbacCfg.GetRules().GetPolicies() {
for _, principal := range policy.Principals {View on GitHub (pinned to 03255a9237)
Solutions
- Remove header matchers on ':scheme' and any 'grpc-'-prefixed header from RBAC principals (and permissions, which are checked similarly).
- If you need to gate on gRPC metadata, match on the corresponding well-known metadata via supported mechanisms rather than raw header names.
- Validate generated RBAC policies against the A41 restrictions before publishing.
Example fix
// before
policy.Principals = append(policy.Principals, &rbacpb.Principal{Identifier: &rbacpb.Principal_Header{Header: &routepb.HeaderMatcher{Name: ":scheme"}}})
// after: drop the unsupported header matcher (or match a supported header)
policy.Principals = append(policy.Principals, &rbacpb.Principal{Identifier: &rbacpb.Principal_Header{Header: &routepb.HeaderMatcher{Name: ":authority"}}}) Defensive patterns
Strategy: validation
Validate before calling
for _, p := range rbacCfg.GetRules().GetPolicies() {
for _, pr := range p.GetPrincipals() {
n := pr.GetHeader().GetName()
if n == ":scheme" || strings.HasPrefix(n, "grpc-") {
return fmt.Errorf("unsupported header matcher: %s", n)
}
}
} Try / catch
fc, err := builder{}.ParseFilterConfig(anyMsg)
if err != nil {
return err
} Prevention
- Do not match on ':scheme' or 'grpc-'-prefixed headers in RBAC policies.
- Validate generated RBAC against gRFC A41 restrictions before publishing.
- Prefer supported matchers (e.g. ':authority') for header-based authz.
When it happens
Trigger: An RBAC rules policy contains a Principal.Identifier.header with name ':scheme' or a name beginning with 'grpc-'.
Common situations: RBAC config ported from Envoy/HTTP semantics that matched scheme or grpc metadata headers; generic header-based authz policy; template that lists all headers as matchers.
Related errors
- gcpauthn: cache_config.cache_size must be greater than zero
- missing server_listener_resource_name_template in the bootst
- wrr: errorUtilizationPenalty must be non-negative
- %s: %v
- OutlierDetectionLoadBalancingConfig.interval = %s; must be >
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/d76328f9ff4650c2.
Report an issue: GitHub.