grpc/grpc-go · error
rbac: header matcher for %q starts with %q
Error message
rbac: header matcher for %q starts with %q
What it means
normalizeHeaderMatcher (rbac.go:176) rejects a header matcher whose name starts with "grpc-". Per gRFC A41, these headers are reserved for the gRPC transport and must not be matched by RBAC policies.
Source
Thrown at internal/xds/httpfilter/rbac/rbac.go:177
if err := normalizePrincipalHeaders(id); err != nil {
return err
}
}
case *v3rbacpb.Principal_NotId:
return normalizePrincipalHeaders(p.NotId)
}
return nil
}
// normalizeHeaderMatcher rejects header matchers that A41 forbids (:scheme or a
// grpc- prefixed name) and rewrites a "host" matcher to ":authority".
func normalizeHeaderMatcher(header *v3routepb.HeaderMatcher) error {
name := header.GetName()
if name == ":scheme" {
return fmt.Errorf("rbac: header matcher for %q is %q", name, ":scheme")
}
if strings.HasPrefix(name, "grpc-") {
return fmt.Errorf("rbac: header matcher for %q starts with %q", name, "grpc-")
}
if name == "host" {
header.Name = ":authority"
}
return nil
}
func (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {
if cfg == nil {
return nil, fmt.Errorf("rbac: nil configuration message provided")
}
m, ok := cfg.(*anypb.Any)
if !ok {
return nil, fmt.Errorf("rbac: error parsing config %v: unknown type %T", cfg, cfg)
}
msg := new(rpb.RBAC)
if err := m.UnmarshalTo(msg); err != nil {
return nil, fmt.Errorf("rbac: error parsing config %v: %v", cfg, err)View on GitHub (pinned to 0c51461d27)
Solutions
- Remove the grpc-* header matcher from the policy.
- If you need to gate on tracing metadata, do it in the application or via a different filter.
- Audit all HeaderMatcher entries for the grpc- prefix during policy authoring.
Example fix
// before
permissions: [{ rule: { header: { name: "grpc-trace-bin", present_match: true } } }]
// after
// (matcher removed) Defensive patterns
Strategy: validation
Validate before calling
func validateNoGrpcHeaders(p *v3rbacpb.Policy) error {
check := func(h *v3routepb.HeaderMatcher) error {
if strings.HasPrefix(h.GetName(), "grpc-") { return fmt.Errorf("grpc-* header %q forbidden by A41", h.GetName()) }
return nil
}
/* walk principals+permissions as the filter does */
return nil
} Try / catch
if err != nil && strings.Contains(err.Error(), "starts with") {
// remove the grpc-* header matcher from the policy
} Prevention
- Lint RBAC policies for the grpc- prefix before publishing.
- Handle tracing/auth metadata outside RBAC.
When it happens
Trigger: Any policy permission or principal (including nested and/or/not rules) contains a HeaderMatcher with a name beginning with "grpc-" (e.g., grpc-trace-bin, grpc-status, grpc-encoding).
Common situations: Operator copies an Envoy policy that filters on grpc-trace-bin; legacy RBAC config predating A41; policy generator that enumerates all known headers.
Related errors
- rbac: header matcher for %q is %q
- server-side auth info is not of type alts.AuthInfo
- rbac: error constructing matching engine: %v
- no SubConn is available
- all SubConns are in TransientFailure
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/7fd28dde71cdc937.
Report an issue: GitHub.