grpc/grpc-go · error
rbac: permission header matcher for %v is :scheme or starts
Error message
rbac: permission header matcher for %v is :scheme or starts with grpc
What it means
Raised by the RBAC HTTP filter's config validation (gRFC A41). A policy Permission is rejected if it contains a header matcher whose name is the ":scheme" pseudo-header or starts with "grpc-", because those headers are transport-managed in gRPC and cannot be meaningfully matched. The check happens in parseConfig while iterating policy.Permissions.
Source
Thrown at internal/xds/httpfilter/rbac/rbac.go:81
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 {
if principal.GetHeader().GetName() == "host" {
principal.GetHeader().Name = ":authority"
}
}
for _, permission := range policy.Permissions {
if permission.GetHeader().GetName() == "host" {View on GitHub (pinned to 03255a9237)
Solutions
- Remove the offending header matcher from the Permission in the RBAC policy.
- If you need to gate on gRPC metadata, use a Principal-based metadata matcher or a non-header matcher (path, method, destination_ip) instead of matching ":scheme" or grpc-* headers.
- Redeploy the control-plane LDS resource and confirm the new config reaches the server.
Example fix
// before (Envoy RBAC policy fragment)
// permissions:
// - header:
// name: grpc-status
// safe_regex_match: { regex: ".*" }
//
// after
// permissions:
// - url_header:
// name: :path
// safe_regex_match: { regex: "/pkg.Service/Method" } Defensive patterns
Strategy: validation
Validate before calling
// Validate an RBAC policy before sending it from a control plane.
func validateRBACPolicy(rbac *rbacpb.RBAC) error {
for _, policy := range rbac.GetRules().GetPolicies() {
for _, p := range policy.Permissions {
name := p.GetHeader().GetName()
if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
return fmt.Errorf("permission header matcher %q is reserved", name)
}
}
for _, pr := range policy.Principals {
name := pr.GetHeader().GetName()
if name == ":scheme" || strings.HasPrefix(name, "grpc-") {
return fmt.Errorf("principal header matcher %q is reserved", name)
}
}
}
return nil
} Prevention
- Lint RBAC policies on the control plane before serving them (reject ":scheme" and grpc-* header matchers).
- Do not port Envoy HTTP RBAC rules into gRPC verbatim; re-audit header matcher names.
When it happens
Trigger: An xDS RBAC policy delivered via LDS whose Permission list contains a header matcher with name ":scheme" or any name beginning with "grpc-" (e.g. grpc-status, grpc-encoding, grpc-trace-bin).
Common situations: Porting an Envoy HTTP RBAC rule verbatim into a gRPC xDS setup; Istio/Envoy authoring rules that attempt to match on gRPC reserved metadata; control-plane upgrade that emits previously-tolerated matchers.
Related errors
- missing fallback credentials
- rbac: error constructing matching engine: %v
- rbac: nil configuration message provided
- empty token_exchange_service_uri in options
- required field SubjectTokenPath is not specified
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/7f479b9ca2361c2b.
Report an issue: GitHub.