grpc/grpc-java · error · ClassCastException
wrong type
Error message
wrong type
What it means
DnsNameResolver parses gRPC service-config choices from DNS TXT records: each `grpc_config=` TXT record must be JSON whose top level is a list. If the parsed JSON is not a List (e.g. an object or scalar), parseTxtResults throws ClassCastException("wrong type ...") because the record cannot be interpreted as a list of service-config choices.
Solutions
- Fix the DNS TXT record so the value after the `grpc_config=` prefix is a JSON array of service-config choice objects.
- Validate each TXT record with a JSON linter (top level must be `[...]`) before publishing it.
- If multiple TXT records exist, remove the malformed one or set it to a non-`grpc_config` prefix so it is ignored.
Example fix
// before (TXT record)
grpc_config={"serviceConfig":{...}}
// after (TXT record)
grpc_config=[{"serviceConfig":{...}}] Defensive patterns
Strategy: validation
Validate before calling
Object parsed = JsonParser.parse(txtRecord.substring(prefix.length()));
if (!(parsed instanceof List)) throw new IllegalArgumentException("grpc_config TXT must be a JSON array"); Type guard
boolean isJsonArray(Object o) { return o instanceof List; } Try / catch
try {
resolver.resolve(target);
} catch (ClassCastException e) {
// fall back to default service config / retry resolution
} Prevention
- Lint DNS TXT grpc_config records: top level must be a JSON array.
- Use automation with schema validation to publish service-config records.
- Purge stale or hand-edited TXT records.
When it happens
Trigger: A DNS TXT record starting with the gRPC service-config prefix whose JSON value is not an array, e.g. `grpc_config={...}` (object) or `grpc_config=3`, encountered during resolution of the hostname.
Common situations: Misconfigured DNS records published by infrastructure teams; hand-edited TXT entries; service meshes emitting the wrong service-config schema; stale records left over from a config format change.
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
- key ' ' missing in
- Address is not an IP
- "allow_rules" is absent
- Authorization policy should be a JSON object. Found: null
- Can not convert status code
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/178ffb96ed687614.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/io/grpc/internal/DnsNameResolver.java:406
return port;
}
/**
* Parse TXT service config records as JSON.
*
* @throws IOException if one of the txt records contains improperly formatted JSON.
*/
@VisibleForTesting
static List<Map<String, ?>> parseTxtResults(List<String> txtRecords) throws IOException {
List<Map<String, ?>> possibleServiceConfigChoices = new ArrayList<>();
for (String txtRecord : txtRecords) {
if (!txtRecord.startsWith(SERVICE_CONFIG_PREFIX)) {
logger.log(Level.FINE, "Ignoring non service config {0}", new Object[]{txtRecord});
continue;
}
Object rawChoices = JsonParser.parse(txtRecord.substring(SERVICE_CONFIG_PREFIX.length()));
if (!(rawChoices instanceof List)) {
throw new ClassCastException("wrong type " + rawChoices);
}
List<?> listChoices = (List<?>) rawChoices;
possibleServiceConfigChoices.addAll(JsonUtil.checkObjectList(listChoices));
}
return possibleServiceConfigChoices;
}
@Nullable
private static final Double getPercentageFromChoice(Map<String, ?> serviceConfigChoice) {
return JsonUtil.getNumberAsDouble(serviceConfigChoice, SERVICE_CONFIG_CHOICE_PERCENTAGE_KEY);
}
@Nullable
private static final List<String> getClientLanguagesFromChoice(
Map<String, ?> serviceConfigChoice) {
return JsonUtil.getListOfStrings(
serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_LANGUAGE_KEY);
}View on GitHub (pinned to 64daddc1f3)