grpc/grpc-java · error · IllegalArgumentException

Header name length must be in range [1, 16384): ${length}

Error message

Header name length must be in range [1, 16384): ${length}

What it means

The HeaderMatchInput constructor validates header names used as xDS HttpRequestHeaderMatchInput: a name must be non-empty and shorter than 16384 characters, matching HTTP header name limits. Names that are empty or too long cannot appear in a valid HTTP request, so the constructor rejects them immediately with IllegalArgumentException and the offending length.

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/HeaderMatchInput.java:43

import io.grpc.Metadata;
import java.util.Locale;

/**
 * MatchInput for extracting HTTP headers.
 */
final class HeaderMatchInput implements MatchInput {
  private static final BaseEncoding BASE64 = BaseEncoding.base64();
  private final String headerName;
  private final Metadata.Key<byte[]> binaryKey;
  private final Metadata.Key<String> stringKey;

  static final String TYPE_URL =
      "type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput";
    
  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);
    }
  }
    

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Ensure the header name is a valid non-empty HTTP header name, e.g. "x-user-id".
  2. Validate length (1..16383) on the config producer before emitting the matcher input.
  3. Catch IllegalArgumentException around HeaderMatchInput construction and reject the config with the root cause.

Example fix

// before
new HeaderMatchInput("");
// after
if (name == null || name.isEmpty() || name.length() >= 16384) throw new ConfigException("bad header name");
new HeaderMatchInput(name);
Defensive patterns

Strategy: validation

Validate before calling

if (name == null || name.isEmpty() || name.length() >= 16384)
  throw new IllegalArgumentException("header name length must be in [1, 16384)");

Type guard

boolean isValidHeaderNameLength(String name) {
  return name != null && !name.isEmpty() && name.length() < 16384;
}

Try / catch

try { return new HeaderMatchInput(name); }
catch (IllegalArgumentException e) { logger.warn("bad header name", e); return null; }

Prevention

When it happens

Trigger: Constructing HeaderMatchInput with "" (length 0) or a name whose length() >= 16384; the check is headerName.isEmpty() || headerName.length() >= 16384.

Common situations: Config generators emitting empty header-name fields; pathological or corrupted xDS configs; programmatic construction with unvalidated user-supplied header names; truncation/concatenation bugs producing huge strings.

Related errors


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