grpc/grpc-java · error · IllegalArgumentException

Invalid header matcher config: [grpc-] prefixed header name

Error message

Invalid header matcher config: [grpc-] prefixed header name is not allowed.

What it means

This error is thrown by RbacFilter.parseHeaderMatcher when an xDS RBAC policy's header matcher specifies a header name starting with the reserved 'grpc-' prefix. The gRPC-internal 'grpc-*' metadata keys are reserved for the transport and must not be matched by RBAC rules, so the config is rejected at parse time with IllegalArgumentException.

Source

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

    switch (proto.getRuleCase()) {
      case PATH:
        return PathMatcher.create(MatcherParser.parseStringMatcher(proto.getPath()));
      case RULE_NOT_SET:
      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);
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Remove or rename the header matcher so it does not use a name starting with 'grpc-'
  2. Match on a non-reserved application header instead (e.g. custom 'x-' headers)
  3. Validate header names before submitting the xDS config to the management server

Example fix

// before
{"header": {"name": "grpc-timeout", "exactMatch": "10s"}}
// after
{"header": {"name": "x-request-tier", "exactMatch": "premium"}}
Defensive patterns

Strategy: validation

Validate before calling

if (headerMatcher.getName().startsWith("grpc-")) {
  throw new IllegalArgumentException("Reserved grpc- header name not allowed in RBAC matcher: " + headerMatcher.getName());
}

Prevention

When it happens

Trigger: Parsing an xDS RBAC config (via parsePermission or parsePrincipal) whose v3 HeaderMatcher proto has name like 'grpc-timeout' or 'grpc-encoding'.

Common situations: Hand-written RBAC policy JSON/YAML copied from HTTP proxy configs that reference grpc-* headers; tools generating RBAC policies that include internal gRPC transport headers.

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/3c1925211c6eb6c3. Report an issue: GitHub.