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
- 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)
- If you wrap or proxy sockets, unwrap to the underlying SSLSocket before it reaches the SSLEngine/SSLSocket verification path
- 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
- 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
- Only install AdvancedTlsX509TrustManager in SSLContexts used for TLS connections
- Prefer the SSLEngine-based trust-manager path (X509ExtendedTrustManager) used by modern stacks
- Unwrap wrapped/proxied sockets to the underlying SSLSocket
- Do not reuse a TLS-configured SSLContext for plaintext sockets
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
- This method is deprecated and marked for removal. Use the ge
- TLS Provider failure
- Cannot verify hostname: ${host}
- Can't set TLS settings for ALTS
- A key manager is required
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/82d5b20016bfb3fa.
Report an issue: GitHub.