grpc/grpc-java · error · RuntimeException

Unexpected error converting ChannelCredentials to Netty SslC

Error message

Unexpected error converting ChannelCredentials to Netty SslContext: ${ex}

What it means

When TLS is negotiated but no explicit SslContext was supplied, newNegotiator() builds a default client SslContext via GrpcSslContexts.forClient().build(). An SSLException during that build is wrapped and rethrown as an unchecked RuntimeException with message "Unexpected error converting ChannelCredentials to Netty SslContext" (the original SSLException as cause).

Source

Thrown at netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java:783



  static Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
    return Collections.singleton(InetSocketAddress.class);
  }

  private final class DefaultProtocolNegotiator implements ProtocolNegotiator.ClientFactory {
    private NegotiationType negotiationType = NegotiationType.TLS;
    private SslContext sslContext;

    @Override
    public ProtocolNegotiator newNegotiator() {
      SslContext localSslContext = sslContext;
      if (negotiationType == NegotiationType.TLS && localSslContext == null) {
        try {
          localSslContext = GrpcSslContexts.forClient().build();
        } catch (SSLException ex) {
          throw new RuntimeException(ex);
        }
      }
      return createProtocolNegotiatorByType(negotiationType, localSslContext,
          managedChannelImplBuilder.getOffloadExecutorPool());
    }

    @Override
    public int getDefaultPort() {
      switch (negotiationType) {
        case PLAINTEXT:
        case PLAINTEXT_UPGRADE:
          return GrpcUtil.DEFAULT_PORT_PLAINTEXT;
        case TLS:
          return GrpcUtil.DEFAULT_PORT_SSL;
        default:
          throw new AssertionError(negotiationType + " not handled");
      }
    }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Inspect the cause (SSLException) to find the underlying TLS provider problem.
  2. Explicitly build and set an SslContext: GrpcSslContexts.forClient().trustManager(caFile).build(), then call sslContext(...) on the builder.
  3. Add/align netty-tcnative-boringssl-static or Conscrypt with the netty version, or fall back to the JDK provider via SslProvider/JDK.
  4. Ensure a full JDK (proper security providers, unlimited crypto policy) is used.

Example fix

// before
ManagedChannel ch = NettyChannelBuilder.forAddress("host", 443).build(); // TLS default, implicit SslContext
// after
SslContext sslCtx = GrpcSslContexts.forClient()
    .trustManager(new File("ca.pem"))
    .build();
ManagedChannel ch = NettyChannelBuilder.forAddress("host", 443)
    .sslContext(sslCtx)
    .build();
Defensive patterns

Strategy: try-catch

Validate before calling

if (builder-useTls) {
  try {
    SslContext ctx = GrpcSslContexts.forClient().build(); // fail early, before channel build
  } catch (SSLException e) { /* fix provider/trust setup */ }
}

Try / catch

try {
  ManagedChannel ch = builder.build();
} catch (RuntimeException e) {
  if (e.getCause() instanceof SSLException) {
    // TLS provider/environment problem: configure explicit SslContext or switch SslProvider
  }
}

Prevention

When it happens

Trigger: Calling build() on a NettyChannelBuilder whose negotiationType is TLS with sslContext unset, when GrpcSslContexts.forClient().build() throws SSLException — typically due to missing TLS provider support, an empty/broken default trust manager setup, or an incompatible OpenSSL (netty-tcnative) configuration.

Common situations: Missing or mismatched netty-tcnative/boringssl native library so the default provider fails; JVM without the crypto primitives GrpcSslContexts expects; custom Conscrypt/tcnative versions conflicting; restricted crypto policy environments.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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