grpc/grpc-java · error · GrpcServiceParseException

Invalid initial metadata header: ${key}

Error message

Invalid initial metadata header: ${key}

What it means

Thrown by GrpcServiceConfigParser.parse when an initial_metadata header from the GrpcService proto cannot be converted into a Metadata.HeaderValue — HeaderValue.create threw IllegalArgumentException (e.g. invalid header name characters) — or the header is rejected by HeaderValueValidationUtils.isDisallowed. gRPC forbids malformed or reserved headers in injected metadata.

Source

Thrown at xds/src/main/java/io/grpc/xds/GrpcServiceConfigParser.java:108

    }
    GrpcServiceConfig.GoogleGrpcConfig googleGrpcConfig =
        parseGoogleGrpcConfig(grpcServiceProto.getGoogleGrpc(), bootstrapInfo, serverInfo);

    GrpcServiceConfig.Builder builder = GrpcServiceConfig.builder().googleGrpc(googleGrpcConfig);

    ImmutableList.Builder<HeaderValue> initialMetadata = ImmutableList.builder();
    for (io.envoyproxy.envoy.config.core.v3.HeaderValue header : grpcServiceProto
        .getInitialMetadataList()) {
      String key = header.getKey();
      HeaderValue headerValue;
      try {
        if (key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
          headerValue = HeaderValue.create(key, header.getRawValue());
        } else {
          headerValue = HeaderValue.create(key, header.getValue());
        }
      } catch (IllegalArgumentException e) {
        throw new GrpcServiceParseException("Invalid initial metadata header: " + key, e);
      }
      if (HeaderValueValidationUtils.isDisallowed(headerValue)) {
        throw new GrpcServiceParseException("Invalid initial metadata header: " + key);
      }
      initialMetadata.add(headerValue);
    }
    builder.initialMetadata(initialMetadata.build());

    if (grpcServiceProto.hasTimeout()) {
      com.google.protobuf.Duration timeout = grpcServiceProto.getTimeout();
      if (!Durations.isValid(timeout) || Durations.compare(timeout, Durations.ZERO) <= 0) {
        throw new GrpcServiceParseException("Timeout must be strictly positive and valid");
      }
      builder.timeout(Duration.ofSeconds(timeout.getSeconds(), timeout.getNanos()));
    }
    return builder.build();
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Fix the header key/value in the xDS resource: use lowercase, valid header names and legal values.
  2. Remove or rename disallowed/reserved headers (e.g. host, content-length) from initial_metadata.
  3. For binary data, use a key ending in '-bin' and supply raw_value instead of value.
  4. Inspect the GrpcService proto received from the control plane to identify the offending key named in the message.

Example fix

// before (xDS resource)
initial_metadata { key: "Host" value: "example.com" }
// after
initial_metadata { key: "x-custom-host" value: "example.com" }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate header keys before pushing them via xDS
String key = header.getKey();
if (key == null || key.isEmpty() || !key.chars().allMatch(c ->
    (c >= 'a' && c <= '9' && c != ':') || c == '-' || (c >= '0' && c <= '9'))) {
  throw new IllegalArgumentException("bad metadata header key: " + key);
}

Try / catch

try {
  config = GrpcServiceConfigParser.parse(proto, bootstrapInfo, serverInfo);
} catch (GrpcServiceParseException e) {
  if (e.getMessage().startsWith("Invalid initial metadata header")) {
    logger.log(WARNING, "Rejecting resource with bad header: " + e.getMessage());
  }
}

Prevention

When it happens

Trigger: xDS GrpcService.google_grpc.call_credentials or channel config includes initial_metadata whose key is malformed (invalid characters, wrong case rules for binary headers missing the -bin suffix handling) or whose value fails validation; also fires when the header is on the disallowed list (e.g. reserved headers like :authority, host, content-length).

Common situations: Control-plane configuration injecting headers such as 'host', 'authorization' in disallowed forms, or binary values sent as regular (non -bin) headers; typos producing illegal ASCII control characters in keys.

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


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