grpc/grpc-java · error · IllegalArgumentException
Invalid header name: ${headerName}
Error message
Invalid header name: ${headerName} What it means
HeaderMatchInput validates an xDS header name by constructing a Metadata.Key; if the name is not a valid gRPC metadata key (must be lowercase ASCII letters, digits, hyphen, underscore, and dot), the underlying IllegalArgumentException is rethrown wrapped with the offending header name. This prevents invalid header names from silently failing to match at runtime.
Source
Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/HeaderMatchInput.java:58
HeaderMatchInput(String headerName) {
this.headerName = checkNotNull(headerName, "headerName");
if (headerName.isEmpty() || headerName.length() >= 16384) {
throw new IllegalArgumentException(
"Header name length must be in range [1, 16384): " + headerName.length());
}
if (!headerName.equals(headerName.toLowerCase(Locale.ROOT))) {
throw new IllegalArgumentException("Header name must be lowercase: " + headerName);
}
try {
if (headerName.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
this.binaryKey = Metadata.Key.of(headerName, Metadata.BINARY_BYTE_MARSHALLER);
this.stringKey = null;
} else {
this.binaryKey = null;
this.stringKey = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER);
}
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid header name: " + headerName, e);
}
}
@Override
public String apply(MatchContext context) {
if ("te".equals(headerName)) {
return null;
}
if (binaryKey != null) {
Iterable<byte[]> values = context.getMetadata().getAll(binaryKey);
if (values == null) {
return null;
}
StringBuilder sb = new StringBuilder();
boolean first = true;
for (byte[] value : values) {
if (!first) {
sb.append(",");View on GitHub (pinned to 64daddc1f3)
Solutions
- Check the header_name in the xDS HttpHeaderMatchInput config: it must be lowercase and only contain letters, digits, '-', '_', '.'.
- Lowercase and sanitize the header name (e.g. X-Request-Id -> x-request-id).
- If the name is dynamic, validate it before building the matcher with a regex like ^[a-z0-9_.-]+$.
Example fix
// before
{"header_name": "X-Request-Id"}
// after
{"header_name": "x-request-id"} Defensive patterns
Strategy: validation
Validate before calling
static boolean isValidHeaderName(String name) {
return name != null && name.matches("^[a-z0-9_.-]+$");
}
if (!isValidHeaderName(cfg.getHeaderName())) throw new IllegalArgumentException("bad header name: " + cfg.getHeaderName()); Type guard
static boolean isValidHeaderName(String name) {
return name != null && name.matches("^[a-z0-9_.-]+$");
} Try / catch
try {
input = factory.getInput(config);
} catch (IllegalArgumentException e) {
logger.warn("bad header match input: " + e.getMessage());
throw new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(e.getMessage()));
} Prevention
- Always lowercase header names in generated xDS configs
- Validate header_name against ^[a-z0-9_.-]+$ before sending config
- Reject invalid headers at the management server, not just the client
When it happens
Trigger: Calling getInput with a TypedExtensionConfig whose HttpRequestHeaderMatchInput.header_name contains characters invalid for gRPC metadata keys (e.g. uppercase letters, spaces, colons) or is empty.
Common situations: Copy-pasting Envoy route config with HTTP-style header names like 'X-Request-Id' (uppercase not allowed for metadata keys) or hand-written CEL/rbac matcher configs with typos in the header name.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- unsupported ExtAuthz service type: only grpc_service is supp
- Invalid ring hash function: " + ringHash.getHashFunction()
- Custom LB config does not contain a JSON object
- Invalid header matcher config: [grpc-] prefixed header name
- Invalid header matcher config: header name [:scheme] is not
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/6ca0791b789aa40d.
Report an issue: GitHub.