grpc/grpc-java · error · IllegalArgumentException

Invalid header matcher config: header name [:scheme] is not

Error message

Invalid header matcher config: header name [:scheme] is not allowed.

What it means

This error is thrown by RbacFilter.parseHeaderMatcher when an xDS RBAC header matcher targets the pseudo-header ':scheme'. The :scheme pseudo-header is controlled by the transport/TLS layer, not the application, so RBAC rules may not match on it and the config is rejected at parse time.

Source

Thrown at xds/src/main/java/io/grpc/xds/RbacFilter.java:329

      default:
        throw new IllegalArgumentException(
                "Unknown path matcher rule type: " + proto.getRuleCase());
    }
  }

  private static RequestedServerNameMatcher parseRequestedServerNameMatcher(
          io.envoyproxy.envoy.type.matcher.v3.StringMatcher proto) {
    return RequestedServerNameMatcher.create(MatcherParser.parseStringMatcher(proto));
  }

  private static AuthHeaderMatcher parseHeaderMatcher(
          io.envoyproxy.envoy.config.route.v3.HeaderMatcher proto) {
    if (proto.getName().startsWith("grpc-")) {
      throw new IllegalArgumentException("Invalid header matcher config: [grpc-] prefixed "
          + "header name is not allowed.");
    }
    if (":scheme".equals(proto.getName())) {
      throw new IllegalArgumentException("Invalid header matcher config: header name [:scheme] "
          + "is not allowed.");
    }
    return AuthHeaderMatcher.create(MatcherParser.parseHeaderMatcher(proto));
  }

  private static AuthenticatedMatcher parseAuthenticatedMatcher(
          Principal.Authenticated proto) {
    Matchers.StringMatcher matcher = MatcherParser.parseStringMatcher(proto.getPrincipalName());
    return AuthenticatedMatcher.create(matcher);
  }

  private static DestinationPortMatcher createDestinationPortMatcher(int port) {
    return DestinationPortMatcher.create(port);
  }

  private static DestinationPortRangeMatcher parseDestinationPortRangeMatcher(Int32Range range) {
    return DestinationPortRangeMatcher.create(range.getStart(), range.getEnd());
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Remove the ':scheme' header matcher from the RBAC policy
  2. Use a destination port matcher or other permission type to restrict by transport characteristics instead
  3. Match on an application-level header set by the client

Example fix

// before
{"orRules": {"rules": [{"header": {"name": ":scheme", "exactMatch": "https"}}]}}
// after
{"destinationPort": 443}
Defensive patterns

Strategy: validation

Validate before calling

if (":scheme".equals(headerMatcher.getName())) {
  throw new IllegalArgumentException(":scheme is not allowed in RBAC header matchers");
}

Prevention

When it happens

Trigger: Parsing an xDS RBAC permission/principal containing a HeaderMatcher whose name is exactly ':scheme'.

Common situations: Porting Envoy RBAC configs that legitimately match :scheme in HTTP filter contexts to gRPC's RBAC filter, where it is disallowed; attempts to restrict policies to https-only traffic via header matching.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/21e4cf633f7d5dd2. Report an issue: GitHub.