grpc/grpc-java · error · RuntimeException
Unknown negotiation type: ${negotiationType}
Error message
Unknown negotiation type: ${negotiationType} What it means
Thrown when the channel builder's negotiationType is neither TLS nor PLAINTEXT. Since NegotiationType is an enum, this usually only occurs through reflection, deserialization of a corrupted enum, or future enum values not handled by this switch.
Source
Thrown at okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java:614
@VisibleForTesting
@Nullable
SSLSocketFactory createSslSocketFactory() {
switch (negotiationType) {
case TLS:
try {
if (sslSocketFactory == null) {
SSLContext sslContext = SSLContext.getInstance("Default", Platform.get().getProvider());
sslSocketFactory = sslContext.getSocketFactory();
}
return sslSocketFactory;
} catch (GeneralSecurityException gse) {
throw new RuntimeException("TLS Provider failure", gse);
}
case PLAINTEXT:
return null;
default:
throw new RuntimeException("Unknown negotiation type: " + negotiationType);
}
}
private static final EnumSet<TlsChannelCredentials.Feature> understoodTlsFeatures =
EnumSet.of(
TlsChannelCredentials.Feature.MTLS, TlsChannelCredentials.Feature.CUSTOM_MANAGERS);
static SslSocketFactoryResult sslSocketFactoryFrom(ChannelCredentials creds) {
if (creds instanceof TlsChannelCredentials) {
TlsChannelCredentials tlsCreds = (TlsChannelCredentials) creds;
Set<TlsChannelCredentials.Feature> incomprehensible =
tlsCreds.incomprehensible(understoodTlsFeatures);
if (!incomprehensible.isEmpty()) {
return SslSocketFactoryResult.error(
"TLS features not understood: " + incomprehensible);
}View on GitHub (pinned to 64daddc1f3)
Solutions
- Only pass NegotiationType.TLS or NegotiationType.PLAINTEXT to negotiationType()
- Rebuild against a consistent grpc-okhttp version to fix enum binary-compatibility issues
- Check ProGuard/R8 rules keep enum values intact
- If a new constant was added upstream, upgrade grpc-okhttp where the switch handles it
Example fix
// before
builder.negotiationType(someUnrecognizedType);
// after
if (negotiationType == NegotiationType.TLS || negotiationType == NegotiationType.PLAINTEXT) {
builder.negotiationType(negotiationType);
} else {
builder.usePlaintext();
} Defensive patterns
Strategy: validation
Validate before calling
Set<NegotiationType> valid = EnumSet.of(NegotiationType.TLS, NegotiationType.PLAINTEXT); if (!valid.contains(type)) throw new IllegalArgumentException("bad negotiation type"); Type guard
boolean isKnownNegotiationType(NegotiationType t) { return t == NegotiationType.TLS || t == NegotiationType.PLAINTEXT; } Try / catch
try { buildTransportFactory(); } catch (RuntimeException e) { if (e.getMessage().startsWith("Unknown negotiation type")) { fallbackToPlaintextOrTls(); } else { throw e; } } Prevention
- Only use NegotiationType enum constants from your compiled grpc version
- Keep grpc-okhttp versions consistent across modules
- Add keep rules for grpc enums in ProGuard/R8
When it happens
Trigger: Invoking builder.negotiationType() with an unhandled NegotiationType value (e.g. via reflection, code generation, or after a library upgrade where a new enum constant exists), then calling buildTransportFactory.
Common situations: Binary-incompatible upgrades between grpc versions, reflection-based configuration, ProGuard/R8 enum obfuscation bugs, hand-rolled channel construction.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Unable to load OkHttpChannelProvider
- Unsupported provider: ${provider}
- Unsupported negotiationType: ${negotiationType}
- closed
- Unable to perform write due to unavailable sink.
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/3563b49cdf143c21.
Report an issue: GitHub.