grpc/grpc-java · error · VerifyException

Can not convert status code

Error message

Can not convert status code ${status} to Status.Code, because its type is ${type}

What it means

In ServiceConfigUtil.getStatusCodesFromList, each status entry must be a String naming a Status.Code or an Integer code value. If the JSON entry is neither (e.g. a boolean, nested object, or null), this VerifyException reports the unexpected type. The library throws it to reject malformed service configs early rather than fail obscurely later.

Solutions

  1. Inspect the retryableStatusCodes array in the service config and ensure every element is a string (status name) or integer (code value)
  2. Remove null/boolean/object entries or convert them to proper code names like "DEADLINE_EXCEEDED"
  3. Validate the service config JSON against the gRPC service config schema before deployment

Example fix

// before
"retryableStatusCodes": ["UNAVAILABLE", {"code": 14}]
// after
"retryableStatusCodes": ["UNAVAILABLE", "RESOURCE_EXHAUSTED"]
Defensive patterns

Strategy: type-guard

Validate before calling

// Before parsing, check element types
for (Object o : rawList) {
  if (!(o instanceof String) && !(o instanceof Integer)) {
    throw new IllegalArgumentException("retryableStatusCodes entries must be string or int, got: "
        + (o == null ? "null" : o.getClass().getSimpleName()));
  }
}

Type guard

boolean isValidStatusCodeEntry(Object o) {
  return o instanceof String || o instanceof Integer;
}

Try / catch

try {
  codes = ServiceConfigUtil.getListOfStatusCodesAsSet(rawList);
} catch (VerifyException e) {
  log.error("retryableStatusCodes contains non string/int entry");
  throw new ConfigInvalidException(e);
}

Prevention

When it happens

Trigger: A retryableStatusCodes entry in the service config is a non-string, non-integer JSON value such as true, null, {"code":14}, or [14]; reached via getListOfStatusCodesAsSet during service config parsing.

Common situations: Malformed service config where status codes were nested in objects or left as booleans/null; templating tools that substituted placeholder values incorrectly; YAML/JSON conversion mistakes.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/io/grpc/internal/ServiceConfigUtil.java:173

  private static Set<Status.Code> getStatusCodesFromList(List<?> statuses) {
    EnumSet<Status.Code> codes = EnumSet.noneOf(Status.Code.class);
    for (Object status : statuses) {
      Status.Code code;
      if (status instanceof Double) {
        Double statusD = (Double) status;
        int codeValue = statusD.intValue();
        verify((double) codeValue == statusD, "Status code %s is not integral", status);
        code = Status.fromCodeValue(codeValue).getCode();
        verify(code.value() == statusD.intValue(), "Status code %s is not valid", status);
      } else if (status instanceof String) {
        try {
          code = Status.Code.valueOf((String) status);
        } catch (IllegalArgumentException iae) {
          throw new VerifyException("Status code " + status + " is not valid", iae);
        }
      } else {
        throw new VerifyException(
            "Can not convert status code " + status + " to Status.Code, because its type is "
                + status.getClass());
      }
      codes.add(code);
    }
    return Collections.unmodifiableSet(codes);
  }

  static Set<Status.Code> getRetryableStatusCodesFromRetryPolicy(Map<String, ?> retryPolicy) {
    String retryableStatusCodesKey = "retryableStatusCodes";
    Set<Status.Code> codes = getListOfStatusCodesAsSet(retryPolicy, retryableStatusCodesKey);
    verify(codes != null, "%s is required in retry policy", retryableStatusCodesKey);
    verify(!codes.contains(Status.Code.OK), "%s must not contain OK", retryableStatusCodesKey);
    return codes;
  }

  @Nullable
  static Integer getMaxAttemptsFromHedgingPolicy(Map<String, ?> hedgingPolicy) {

View on GitHub (pinned to 64daddc1f3)