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
- Remove the ':scheme' header matcher from the RBAC policy
- Use a destination port matcher or other permission type to restrict by transport characteristics instead
- 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
- Exclude HTTP pseudo-headers (prefixed ':') from RBAC policies
- When porting Envoy configs, strip pseudo-header matchers first
- Use destination port or other permission types to constrain by transport
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
- Invalid header matcher config: [grpc-] prefixed header name
- unsupported ExtAuthz service type: only grpc_service is supp
- Invalid ring hash function: " + ringHash.getHashFunction()
- Custom LB config does not contain a JSON object
- Unknown permission rule case: " + permission.getRuleCase()
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/21e4cf633f7d5dd2.
Report an issue: GitHub.