{"record":{"id":"6c8ea51a098576eb","repo":"grpc/grpc-java","slug":"tls-alpn-negotiation-failed-with-protocols-prot","errorCode":null,"errorMessage":"TLS ALPN negotiation failed with protocols: ${protocols}","messagePattern":"TLS ALPN negotiation failed with protocols: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java","lineNumber":106,"sourceCode":"\n  /**\n   * Start and wait until the negotiation is done, returns the negotiated protocol.\n   *\n   * @throws IOException if an IO error was encountered during the handshake.\n   * @throws RuntimeException if the negotiation completed, but no protocol was selected.\n   */\n  public String negotiate(\n      SSLSocket sslSocket, String hostname, @Nullable List<Protocol> protocols) throws IOException {\n    if (protocols != null) {\n      configureTlsExtensions(sslSocket, hostname, protocols);\n    }\n    try {\n      // Force handshake.\n      sslSocket.startHandshake();\n\n      String negotiatedProtocol = getSelectedProtocol(sslSocket);\n      if (negotiatedProtocol == null) {\n        throw new RuntimeException(\"TLS ALPN negotiation failed with protocols: \" + protocols);\n      }\n      return negotiatedProtocol;\n    } finally {\n      platform.afterHandshake(sslSocket);\n    }\n  }\n\n  /** Configure TLS extensions. */\n  protected void configureTlsExtensions(\n      SSLSocket sslSocket, String hostname, List<Protocol> protocols) {\n    platform.configureTlsExtensions(sslSocket, hostname, protocols);\n  }\n\n  /** Returns the negotiated protocol, or null if no protocol was negotiated. */\n  public String getSelectedProtocol(SSLSocket socket) {\n    return platform.getSelectedProtocol(socket);\n  }\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java#L88-L124","documentation":"OkHttpProtocolNegotiator.negotiate forces the SSL handshake and then reads the ALPN/ NPN negotiated protocol; if the socket reports no selected protocol it throws RuntimeException naming the configured protocols. This means TLS succeeded but the peers did not agree on an application protocol (e.g. h2).","triggerScenarios":"Server does not support ALPN or advertises no protocol gRPC requires (h2), client protocol list mismatched, or Android/JDK version lacking ALPN support so getSelectedProtocol returns null.","commonSituations":"Old JDK 7/8 without ALPN support, servers without HTTP/2 enabled, load balancers stripping ALPN, Android versions needing Google Play Services provider.","solutions":["Ensure the server supports HTTP/2 with ALPN and advertises h2","Upgrade to a JDK with ALPN support (8u251+ or 11+), or install Conscrypt as the security provider","Verify no intermediary (LB/proxy) strips ALPN extension","If using custom SSLSocketFactory/sslSocket override, make sure it doesn't disable ALPN"],"exampleFix":"// before\nSSLSocket socket = factory.createSocket(...); // JDK without ALPN\n// after\nSecurity.insertProviderAt(Conscrypt.newProvider(), 1);\nSSLContext ctx = SSLContext.getInstance(\"TLS\", \"Conscrypt\");","handlingStrategy":"fallback","validationCode":"// detect JDK ALPN availability\nboolean alpnOk = Platform.get().getTlsExtensionType() != TlsExtensionType.NONE;","typeGuard":null,"tryCatchPattern":"try { stub.unaryCall(req); } catch (RuntimeException e) { if (e.getMessage().contains(\"ALPN negotiation failed\")) { installConscryptAndRetry(); } throw e; }","preventionTips":["Use JDK 11+ or JDK 8u251+ which ship ALPN","Install Conscrypt on Android/legacy JVMs","Confirm server advertises h2 via ALPN (openssl s_client -alpn h2)"],"tags":["grpc","okhttp","tls","alpn","http2"],"backgroundTag":"tls-handshake-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"}