grpc/grpc-java · error · ResourceInvalidException
HttpConnectionManager with xff_num_trusted_hops unsupported
Error message
HttpConnectionManager with xff_num_trusted_hops unsupported
What it means
gRPC xDS does not implement xff_num_trusted_hops on the HttpConnectionManager, which controls how many trusted proxy hops are counted when interpreting X-Forwarded-For. If the field is nonzero the HCM is considered unsupported and a ResourceInvalidException is thrown, rejecting the Listener.
Source
Thrown at xds/src/main/java/io/grpc/xds/XdsListenerResource.java:499
throw new ResourceInvalidException("Unknown source-type: " + proto.getSourceType());
}
return FilterChainMatch.create(
proto.getDestinationPort().getValue(),
prefixRanges.build(),
ImmutableList.copyOf(proto.getApplicationProtocolsList()),
sourcePrefixRanges.build(),
sourceType,
ImmutableList.copyOf(proto.getSourcePortsList()),
ImmutableList.copyOf(proto.getServerNamesList()),
proto.getTransportProtocol());
}
@VisibleForTesting
static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager(
HttpConnectionManager proto, FilterRegistry filterRegistry,
boolean isForClient, XdsResourceType.Args args) throws ResourceInvalidException {
if (proto.getXffNumTrustedHops() != 0) {
throw new ResourceInvalidException(
"HttpConnectionManager with xff_num_trusted_hops unsupported");
}
if (!proto.getOriginalIpDetectionExtensionsList().isEmpty()) {
throw new ResourceInvalidException("HttpConnectionManager with "
+ "original_ip_detection_extensions unsupported");
}
// Obtain max_stream_duration from Http Protocol Options.
long maxStreamDuration = 0;
if (proto.hasCommonHttpProtocolOptions()) {
HttpProtocolOptions options = proto.getCommonHttpProtocolOptions();
if (options.hasMaxStreamDuration()) {
maxStreamDuration = Durations.toNanos(options.getMaxStreamDuration());
}
}
// Parse http filters.
if (proto.getHttpFiltersList().isEmpty()) {
throw new ResourceInvalidException("Missing HttpFilter in HttpConnectionManager.");View on GitHub (pinned to 64daddc1f3)
Solutions
- Remove xff_num_trusted_hops (or set it to 0) from the http_connection_manager.
- Handle X-Forwarded-For interpretation at an upstream proxy/Envoy layer instead of the gRPC client.
- Split the config so Envoy-managed listeners keep the setting while gRPC-consumed resources do not.
Example fix
// before
http_connection_manager: { xff_num_trusted_hops: 2, ... }
// after
http_connection_manager: { ... } Defensive patterns
Strategy: validation
Validate before calling
if (hcm.getXffNumTrustedHops() != 0) {
throw new IllegalArgumentException("xff_num_trusted_hops unsupported by grpc xds");
} Try / catch
try { applyResource(listener) } catch (ResourceInvalidException e) { if (e.getMessage().contains("xff_num_trusted_hops")) resubmitWithoutXffHops(); } Prevention
- Strip xff_num_trusted_hops from resources destined for gRPC xDS clients
- Keep separate Envoy vs gRPC listener templates
- Validate against gRPC's supported-field allowlist in the control plane
When it happens
Trigger: Listener's http_connection_manager has xff_num_trusted_hops set to a nonzero value, detected in parseHttpConnectionManager (invoked from processClientSideListener or httpConnectionManager parsing).
Common situations: Envoy configs deployed behind multiple load balancers where operators set trusted hops to make XFF parsing correct, shared Envoy templates reused for gRPC xDS listeners, or control planes that propagate the field unconditionally.
Related errors
- HttpConnectionManager with original_ip_detection_extensions
- Listener ${proto.getName()} cannot have listener_filters
- Listener ${proto.getName()} cannot have use_original_dst set
- Missing HttpFilter in HttpConnectionManager.
- HttpConnectionManager contains duplicate HttpFilter: ${filte
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/bfa7793acec4f58d.
Report an issue: GitHub.