grpc/grpc-java · error · SSLPeerUnverifiedException
Cannot verify hostname: ${host}
Error message
Cannot verify hostname: ${host} What it means
After TLS upgrade, OkHttpTlsUpgrader verifies that the peer certificate presented on the SSLSession is valid for the target host using the configured HostnameVerifier. If verification fails, it throws SSLPeerUnverifiedException 'Cannot verify hostname: <host>'.
Source
Thrown at okhttp/src/main/java/io/grpc/okhttp/OkHttpTlsUpgrader.java:71
*/
public static SSLSocket upgrade(SSLSocketFactory sslSocketFactory,
@Nonnull HostnameVerifier hostnameVerifier, Socket socket, String host, int port,
ConnectionSpec spec) throws IOException {
Preconditions.checkNotNull(sslSocketFactory, "sslSocketFactory");
Preconditions.checkNotNull(socket, "socket");
Preconditions.checkNotNull(spec, "spec");
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
socket, host, port, true /* auto close */);
spec.apply(sslSocket, false);
String negotiatedProtocol = OkHttpProtocolNegotiator.get().negotiate(
sslSocket, host, spec.supportsTlsExtensions() ? TLS_PROTOCOLS : null);
Preconditions.checkState(
TLS_PROTOCOLS.contains(Protocol.get(negotiatedProtocol)),
"Only " + TLS_PROTOCOLS + " are supported, but negotiated protocol is %s",
negotiatedProtocol);
if (!hostnameVerifier.verify(canonicalizeHost(host), sslSocket.getSession())) {
throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host);
}
return sslSocket;
}
/**
* Converts a host from URI to X509 format.
*
* <p>IPv6 host addresses derived from URIs are enclosed in square brackets per RFC2732, but
* omit these brackets in X509 certificate subjectAltName extensions per RFC5280.
*
* @see <a href="https://www.ietf.org/rfc/rfc2732.txt">RFC2732</a>
* @see <a href="https://tools.ietf.org/html/rfc5280#section-4.2.1.6">RFC5280</a>
*
* @return {@code host} in a form consistent with X509 certificates
*/
@VisibleForTesting
static String canonicalizeHost(String host) {
if (host.startsWith("[") && host.endsWith("]")) {View on GitHub (pinned to 64daddc1f3)
Solutions
- Obtain a certificate whose subjectAltName matches the exact host you connect to
- Connect using the DNS name on the certificate instead of the raw IP
- Register the host with your internal CA, or supply a custom HostnameVerifier for controlled environments (e.g. tests only)
- Verify with openssl s_client -connect host:443 -servername host that the cert matches
Example fix
// before
channel = OkHttpChannelBuilder.forAddress("10.0.0.5", 443).build();
// after
channel = OkHttpChannelBuilder.forAddress("api.example.com", 443).build(); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight check that a cert matches the host
javax.net.ssl.HttpsURLConnection c = (HttpsURLConnection) new URL("https://" + host + "/").openConnection();
c.setHostnameVerifier(javax.net.ssl.HttpsURLConnection.getDefaultHostnameVerifier());
// attempt handshake or inspect certificate SANs beforehand Type guard
boolean certCoversHost(X509Certificate cert, String host) {
try {
cert.checkValidity();
java.util.Collection<List<?>> sans = cert.getSubjectAlternativeNames();
return sans != null && sans.stream().anyMatch(s -> s.size() > 1 && host.equalsIgnoreCase(String.valueOf(s.get(1))));
} catch (Exception e) { return false; }
} Try / catch
try { upgraded = OkHttpTlsUpgrader.upgrade(...); }
catch (SSLPeerUnverifiedException e) {
log.warn("Certificate does not match host {}: {}", host, e.getMessage());
throw e;
} Prevention
- Issue certificates with SANs for every host/IP clients use
- Prefer DNS names over raw IPs in client configuration
- Only bypass hostname verification in local tests, never production
When it happens
Trigger: HostnameVerifier.verify(canonicalizeHost(host), session) returns false during OkHttpTlsUpgrader.upgrade — typically because the server certificate's SANs do not include the connected hostname, or the hostname is an IP/literal that canonicalizes to something absent from the cert.
Common situations: Connecting via IP address to a cert issued for a DNS name; self-signed or internal CA certs without the right subjectAltName; test certificates lacking SANs; using localhost against a production cert.
Related errors
- TLS Provider failure
- Can't set TLS settings for ALTS
- This method is deprecated and marked for removal. Use the ge
- Unexpected error converting ChannelCredentials to Netty SslC
- Failed to build SSL context from certificate files: ${e}
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/c61bc816decf608f.
Report an issue: GitHub.