grpc/grpc-java · error · ResourceInvalidException

Failed to parse Endpoint metadata

Error message

Failed to parse Endpoint metadata: ${e.getMessage()}

What it means

When parsing each LbEndpoint of an EDS ClusterLoadAssignment, gRPC parses endpoint-level metadata via MetadataRegistry.parseMetadata. If the endpoint's metadata Struct is invalid, the entire EDS resource is rejected with this ResourceInvalidException and the update is NACKed.

Solutions

  1. Read the appended cause message to identify the exact metadata key/value that failed
  2. Correct the per-endpoint metadata Struct in the EDS resource on the management server
  3. Remove unsupported metadata keys or encode values with supported Struct types
  4. Re-send the corrected resource so gRPC ACKs the update

Example fix

// before
lb_endpoints { metadata { fields { key: "weight" value { string_value: "ten" } } } }
// after
lb_endpoints { metadata { fields { key: "weight" value { number_value: 10 } } } }
Defensive patterns

Strategy: validation

Validate before calling

// Control-plane side: validate endpoint metadata before sending
MetadataRegistry registry = MetadataRegistry.getInstance();
for (var lbEndpoint : loadAssignment.getEndpoints(0).getLbEndpointsList()) {
  try {
    registry.parseMetadata(lbEndpoint.getMetadata());
  } catch (ResourceInvalidException e) {
    throw new IllegalStateException("Invalid endpoint metadata: " + e.getMessage(), e);
  }
}

Type guard

boolean isValidEndpointMetadata(com.google.protobuf.Struct metadata) {
  try {
    MetadataRegistry.getInstance().parseMetadata(metadata);
    return true;
  } catch (ResourceInvalidException e) {
    return false;
  }
}

Try / catch

// Client side: capture the NACK reason from the watcher error status
@Override public void onError(Status error) {
  if (error.getDescription().contains("Failed to parse Endpoint metadata")) {
    logger.log(WARNING, "Bad endpoint metadata in EDS resource: " + error.getDescription());
  }
}

Prevention

When it happens

Trigger: An EDS resource arrives where lb_endpoints[i].metadata contains a Struct that fails MetadataRegistry.parseMetadata (unsupported value type, invalid nested structure, or a field violating the metadata schema). The exception is rethrown with this prefix in parseLocalityLbEndpoints.

Common situations: Custom xDS management server attaches endpoint metadata in a non-conforming format; Istio/Envoy emits metadata extensions gRPC does not accept; manually crafted load assignment protos with garbage metadata fields.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at xds/src/main/java/io/grpc/xds/XdsEndpointResource.java:224

    MetadataRegistry registry = MetadataRegistry.getInstance();
    try {
      localityMetadata = registry.parseMetadata(proto.getMetadata());
    } catch (ResourceInvalidException e) {
      throw new ResourceInvalidException("Failed to parse Locality Endpoint metadata: "
          + e.getMessage(), e);
    }
    List<Endpoints.LbEndpoint> endpoints = new ArrayList<>(proto.getLbEndpointsCount());
    for (io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint endpoint : proto.getLbEndpointsList()) {
      // The endpoint field of each lb_endpoints must be set.
      // Inside of it: the address field must be set.
      if (!endpoint.hasEndpoint() || !endpoint.getEndpoint().hasAddress()) {
        return StructOrError.fromError("LbEndpoint with no endpoint/address");
      }
      ImmutableMap<String, Object> endpointMetadata;
      try {
        endpointMetadata = registry.parseMetadata(endpoint.getMetadata());
      } catch (ResourceInvalidException e) {
        throw new ResourceInvalidException("Failed to parse Endpoint metadata: "
            + e.getMessage(), e);
      }
      List<java.net.SocketAddress> addresses = new ArrayList<>();
      addresses.add(getInetSocketAddress(endpoint.getEndpoint().getAddress()));

      if (isEnabledXdsDualStack()) {
        for (Endpoint.AdditionalAddress additionalAddress
            : endpoint.getEndpoint().getAdditionalAddressesList()) {
          addresses.add(getInetSocketAddress(additionalAddress.getAddress()));
        }
      }
      boolean isHealthy = (endpoint.getHealthStatus() == HealthStatus.HEALTHY)
              || (endpoint.getHealthStatus() == HealthStatus.UNKNOWN);
      endpoints.add(Endpoints.LbEndpoint.create(
          new EquivalentAddressGroup(addresses),
          endpoint.getLoadBalancingWeight().getValue(), isHealthy,
          endpoint.getEndpoint().getHostname(),
          endpointMetadata));

View on GitHub (pinned to 64daddc1f3)