grpc/grpc-java · error · CertificateException

socket is not a type of SSLSocket

Error message

socket is not a type of SSLSocket

What it means

AdvancedTlsX509TrustManager performs hostname verification by configuring endpoint identification on the TLS peer. When the transport is not an SSLSocket (and not an SSLEngine, which is handled in the other branch), the manager cannot set the endpoint identification algorithm and throws this CertificateException. It guards against being handed an unexpected socket implementation that cannot support hostname verification.

Source

Thrown at util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java:177

    if (sslEngine == null && socket == null) {
      throw new CertificateException(NOT_ENOUGH_INFO_MESSAGE);
    }
    if (this.verification != Verification.INSECURELY_SKIP_ALL_VERIFICATION) {
      X509ExtendedTrustManager currentDelegateManager = this.delegateManager;
      if (currentDelegateManager == null) {
        throw new CertificateException("No trust roots configured");
      }
      if (checkingServer) {
        String algorithm = this.verification == Verification.CERTIFICATE_AND_HOST_NAME_VERIFICATION
            ? "HTTPS" : "";
        if (sslEngine != null) {
          SSLParameters sslParams = sslEngine.getSSLParameters();
          sslParams.setEndpointIdentificationAlgorithm(algorithm);
          sslEngine.setSSLParameters(sslParams);
          currentDelegateManager.checkServerTrusted(chain, authType, sslEngine);
        } else {
          if (!(socket instanceof SSLSocket)) {
            throw new CertificateException("socket is not a type of SSLSocket");
          }
          SSLSocket sslSocket = (SSLSocket)socket;
          SSLParameters sslParams = sslSocket.getSSLParameters();
          sslParams.setEndpointIdentificationAlgorithm(algorithm);
          sslSocket.setSSLParameters(sslParams);
          currentDelegateManager.checkServerTrusted(chain, authType, sslSocket);
        }
      } else {
        if (sslEngine != null) {
          currentDelegateManager.checkClientTrusted(chain, authType, sslEngine);
        } else {
          currentDelegateManager.checkClientTrusted(chain, authType, socket);
        }
      }
    }
    // Perform the additional peer cert check.
    if (socketAndEnginePeerVerifier != null) {
      if (sslEngine != null) {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Ensure the connection actually uses TLS so the socket passed to the trust manager is an SSLSocket (use an SSLSocketFactory built from an SSLContext configured with this trust manager)
  2. If you wrap or proxy sockets, unwrap to the underlying SSLSocket before it reaches the SSLEngine/SSLSocket verification path
  3. Prefer the checkServerTrusted/checkClientTrusted overloads that accept an SSLEngine, which are used by modern TLS stacks (e.g. via X509ExtendedTrustManager) and avoid the socket branch
  4. Verify you are not registering this trust manager in a non-TLS context such as plain HTTP or a custom protocol

Example fix

// before
Socket socket = new Socket(host, port);
// TLS check on a plain socket fails
// after
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{advancedTlsX509TrustManager}, null);
SSLSocketFactory factory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
Defensive patterns

Strategy: type-guard

Validate before calling

if (socket instanceof SSLSocket) {
  // safe to proceed with AdvancedTlsX509TrustManager
} else {
  throw new IllegalArgumentException("Transport must be TLS: got " + socket.getClass().getName());
}

Type guard

static boolean isTlsSocket(Socket socket) {
  return socket instanceof SSLSocket;
}

Try / catch

try {
  sslContext.init(null, new TrustManager[]{advancedTlsManager}, null);
} catch (CertificateException e) {
  if (e.getMessage().contains("socket is not a type of SSLSocket")) {
    throw new IllegalStateException("Non-TLS transport used with TLS trust manager", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: checkClientTrusted or checkServerTrusted is invoked (via checkTrusted) with a Socket parameter that is not an javax.net.ssl.SSLSocket — e.g. a plaintext socket or a custom/wrapped socket implementation — while the trust manager is installed in an SSLContext used for that connection.

Common situations: Using AdvancedTlsX509TrustManager with a non-TLS socket or a socket wrapped by a proxying/interception layer (monitoring agents, custom SocketFactory); misconfigured SSLContext where the trust manager is applied to non-SSL transports; library versions where the connection provides a raw socket instead of an SSL socket.

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


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