{"record":{"id":"4b09ee5d5d643908","repo":"grpc/grpc-java","slug":"header-name-must-be-lowercase-headername","errorCode":null,"errorMessage":"Header name must be lowercase: ${headerName}","messagePattern":"Header name must be lowercase: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/HeaderMatchInput.java","lineNumber":47,"sourceCode":" * MatchInput for extracting HTTP headers.\n */\nfinal class HeaderMatchInput implements MatchInput {\n  private static final BaseEncoding BASE64 = BaseEncoding.base64();\n  private final String headerName;\n  private final Metadata.Key<byte[]> binaryKey;\n  private final Metadata.Key<String> stringKey;\n\n  static final String TYPE_URL =\n      \"type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput\";\n    \n  HeaderMatchInput(String headerName) {\n    this.headerName = checkNotNull(headerName, \"headerName\");\n    if (headerName.isEmpty() || headerName.length() >= 16384) {\n      throw new IllegalArgumentException(\n          \"Header name length must be in range [1, 16384): \" + headerName.length());\n    }\n    if (!headerName.equals(headerName.toLowerCase(Locale.ROOT))) {\n      throw new IllegalArgumentException(\"Header name must be lowercase: \" + headerName);\n    }\n    try {\n      if (headerName.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {\n        this.binaryKey = Metadata.Key.of(headerName, Metadata.BINARY_BYTE_MARSHALLER);\n        this.stringKey = null;\n      } else {\n        this.binaryKey = null;\n        this.stringKey = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER);\n      }\n    } catch (IllegalArgumentException e) {\n      throw new IllegalArgumentException(\"Invalid header name: \" + headerName, e);\n    }\n  }\n    \n  @Override\n  public String apply(MatchContext context) {\n    if (\"te\".equals(headerName)) {\n      return null;","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/HeaderMatchInput.java#L29-L65","documentation":"HTTP/2 requires header names to be lowercase; this xDS matcher input will look headers up via gRPC Metadata keys, which are case-insensitive-lowercase by convention. HeaderMatchInput therefore rejects mixed/uppercase names with IllegalArgumentException to prevent silently unmatched lookups at request time.","triggerScenarios":"Constructing HeaderMatchInput with a name containing uppercase characters, e.g. \"X-User-Id\", failing the check headerName.equals(headerName.toLowerCase(Locale.ROOT)).","commonSituations":"Configs authored against HTTP/1-style CamelCase header conventions; copy-pasting header names from documentation or browser devtools where names display capitalized; control planes forwarding user-written header names unnormalized.","solutions":["Lowercase the header name before constructing: name.toLowerCase(Locale.ROOT).","Normalize header names on the config producer/control plane before emitting xDS matchers.","Catch IllegalArgumentException and surface a message pointing at the exact offending header name."],"exampleFix":"// before\nnew HeaderMatchInput(\"X-Request-Id\");\n// after\nnew HeaderMatchInput(\"x-request-id\");","handlingStrategy":"validation","validationCode":"String normalized = name.toLowerCase(Locale.ROOT);\nif (!normalized.equals(name)) throw new IllegalArgumentException(\"header name must be lowercase: \" + name);","typeGuard":"boolean isLowercaseHeaderName(String name) {\n  return name != null && name.equals(name.toLowerCase(Locale.ROOT));\n}","tryCatchPattern":"try { return new HeaderMatchInput(name); }\ncatch (IllegalArgumentException e) { logger.warn(\"non-lowercase header: \" + name); return null; }","preventionTips":["Normalize header names with toLowerCase(Locale.ROOT) before construction.","Enforce lowercase header conventions on the control plane.","Never copy CamelCase names from HTTP/1 docs or devtools into xDS matcher configs."],"tags":["grpc-xds","header-validation","http2","case-sensitivity"],"backgroundTag":"invalid-argument-format","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}