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

  1. Only pass NegotiationType.TLS or NegotiationType.PLAINTEXT to negotiationType()
  2. Rebuild against a consistent grpc-okhttp version to fix enum binary-compatibility issues
  3. Check ProGuard/R8 rules keep enum values intact
  4. 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

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


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