{"record":{"id":"c61bc816decf608f","repo":"grpc/grpc-java","slug":"cannot-verify-hostname-host","errorCode":null,"errorMessage":"Cannot verify hostname: ${host}","messagePattern":"Cannot verify hostname: (.+?)","errorType":"exception","errorClass":"SSLPeerUnverifiedException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/OkHttpTlsUpgrader.java","lineNumber":71,"sourceCode":"   */\n  public static SSLSocket upgrade(SSLSocketFactory sslSocketFactory,\n      @Nonnull HostnameVerifier hostnameVerifier, Socket socket, String host, int port,\n      ConnectionSpec spec) throws IOException {\n    Preconditions.checkNotNull(sslSocketFactory, \"sslSocketFactory\");\n    Preconditions.checkNotNull(socket, \"socket\");\n    Preconditions.checkNotNull(spec, \"spec\");\n    SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(\n        socket, host, port, true /* auto close */);\n    spec.apply(sslSocket, false);\n    String negotiatedProtocol = OkHttpProtocolNegotiator.get().negotiate(\n        sslSocket, host, spec.supportsTlsExtensions() ? TLS_PROTOCOLS : null);\n    Preconditions.checkState(\n        TLS_PROTOCOLS.contains(Protocol.get(negotiatedProtocol)),\n        \"Only \" + TLS_PROTOCOLS + \" are supported, but negotiated protocol is %s\",\n        negotiatedProtocol);\n\n    if (!hostnameVerifier.verify(canonicalizeHost(host), sslSocket.getSession())) {\n      throw new SSLPeerUnverifiedException(\"Cannot verify hostname: \" + host);\n    }\n    return sslSocket;\n  }\n\n  /**\n   * Converts a host from URI to X509 format.\n   *\n   * <p>IPv6 host addresses derived from URIs are enclosed in square brackets per RFC2732, but\n   * omit these brackets in X509 certificate subjectAltName extensions per RFC5280.\n   *\n   * @see <a href=\"https://www.ietf.org/rfc/rfc2732.txt\">RFC2732</a>\n   * @see <a href=\"https://tools.ietf.org/html/rfc5280#section-4.2.1.6\">RFC5280</a>\n   *\n   * @return {@code host} in a form consistent with X509 certificates\n   */\n  @VisibleForTesting\n  static String canonicalizeHost(String host) {\n    if (host.startsWith(\"[\") && host.endsWith(\"]\")) {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/OkHttpTlsUpgrader.java#L53-L89","documentation":"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>'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nchannel = OkHttpChannelBuilder.forAddress(\"10.0.0.5\", 443).build();\n// after\nchannel = OkHttpChannelBuilder.forAddress(\"api.example.com\", 443).build();","handlingStrategy":"try-catch","validationCode":"// Pre-flight check that a cert matches the host\njavax.net.ssl.HttpsURLConnection c = (HttpsURLConnection) new URL(\"https://\" + host + \"/\").openConnection();\nc.setHostnameVerifier(javax.net.ssl.HttpsURLConnection.getDefaultHostnameVerifier());\n// attempt handshake or inspect certificate SANs beforehand","typeGuard":"boolean certCoversHost(X509Certificate cert, String host) {\n  try {\n    cert.checkValidity();\n    java.util.Collection<List<?>> sans = cert.getSubjectAlternativeNames();\n    return sans != null && sans.stream().anyMatch(s -> s.size() > 1 && host.equalsIgnoreCase(String.valueOf(s.get(1))));\n  } catch (Exception e) { return false; }\n}","tryCatchPattern":"try { upgraded = OkHttpTlsUpgrader.upgrade(...); }\ncatch (SSLPeerUnverifiedException e) {\n  log.warn(\"Certificate does not match host {}: {}\", host, e.getMessage());\n  throw e;\n}","preventionTips":["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"],"tags":["grpc","java","tls","hostname-verification","ssl"],"backgroundTag":"hostname-verification-failed","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}