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
- Inspect the retryableStatusCodes array in the service config and ensure every element is a string (status name) or integer (code value)
- Remove null/boolean/object entries or convert them to proper code names like "DEADLINE_EXCEEDED"
- 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
- Validate JSON shape (array of string|int) before handing config to gRPC
- Watch for template/placeholder substitution producing nulls or booleans
- Add JSON-schema validation of the service config as a deploy gate
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
- Status code is not valid
- Invalid message type
- Invalid message type
- key ' ' missing in
- The entry ' ' is of type ' ', which is not supported
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)