grpc/grpc-java · error · IllegalArgumentException

Unknown denominator type of ${percent}

Error message

Unknown denominator type of ${percent}

What it means

When converting a drop_overload percentage into a rate-per-million, getRatePerMillion switches on the FractionalPercent denominator. A UNRECOGNIZED or unset denominator hits the default branch and throws IllegalArgumentException, meaning the EDS resource carried a percent value the proto enum could not resolve.

Source

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

      io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy.DropOverload proto) {
    return DropOverload.create(proto.getCategory(), getRatePerMillion(proto.getDropPercentage()));
  }

  private static int getRatePerMillion(FractionalPercent percent) {
    int numerator = percent.getNumerator();
    FractionalPercent.DenominatorType type = percent.getDenominator();
    switch (type) {
      case TEN_THOUSAND:
        numerator *= 100;
        break;
      case HUNDRED:
        numerator *= 10_000;
        break;
      case MILLION:
        break;
      case UNRECOGNIZED:
      default:
        throw new IllegalArgumentException("Unknown denominator type of " + percent);
    }

    if (numerator > 1_000_000 || numerator < 0) {
      numerator = 1_000_000;
    }
    return numerator;
  }


  @VisibleForTesting
  @Nullable
  static StructOrError<LocalityLbEndpoints> parseLocalityLbEndpoints(
      io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints proto)
      throws ResourceInvalidException {
    // Filter out localities without or with 0 weight.
    if (!proto.hasLoadBalancingWeight() || proto.getLoadBalancingWeight().getValue() < 1) {
      return null;
    }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Set denominator explicitly to HUNDRED, TEN_THOUSAND, or MILLION on drop_overload percent
  2. Rebuild/align control-plane protos with the grpc-java xDS proto versions
  3. Validate drop_overload percentages before sending EDS updates
  4. Note this surfaces as IllegalArgumentException (internal), typically causing the EDS watch to fail — fix at the config source

Example fix

# before
drop_overloads:
- category: "lb"
  drop_percentage: { numerator: 5 }   # denominator unset
# after
drop_overloads:
- category: "lb"
  drop_percentage: { numerator: 5, denominator: HUNDRED }
Defensive patterns

Strategy: validation

Validate before calling

for (DropOverload d : assignment.getPolicy().getDropOverloadsList()) {
  if (d.getDropPercentage().getDenominator() == FractionalPercent.DenominatorType.UNRECOGNIZED
      || d.getDropPercentage().getDenominatorValue() == 0) {
    throw new IllegalArgumentException("drop_percentage denominator unset/unknown");
  }
}

Try / catch

try {
  update = XdsEndpointResource.getInstance().parse(args, resource);
} catch (IllegalArgumentException e) {
  logger.warn("Bad drop_overload percent: {}", e.getMessage());
}

Prevention

When it happens

Trigger: parseDropOverload passes a ClusterLoadAssignment drop_overload's FractionalPercent whose denominator is UNRECOGNIZED (unknown enum value from a newer/older proto, or zero-value misuse) into getRatePerMillion.

Common situations: Control plane built against a different protobuf version emitting an enum value grpc-java cannot resolve; hand-crafted drop_overload configs omitting denominator; proto wire corruption yielding UNRECOGNIZED.

Related errors


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