{"record":{"id":"67be5a35428be274","repo":"grpc/grpc-java","slug":"expected-npn-alpn-expectedprotocol-negotiate","errorCode":null,"errorMessage":"Expected NPN/ALPN ${expectedProtocol}: ${negotiatedProtocol}","messagePattern":"Expected NPN/ALPN (.+?): (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/TlsServerHandshakerSocketFactory.java","lineNumber":63,"sourceCode":"\n  @Override\n  public HandshakeResult handshake(Socket socket, Attributes attributes) throws IOException {\n    HandshakeResult result = delegate.handshake(socket, attributes);\n    socket = socketFactory.createSocket(result.socket, null, -1, true);\n    if (!(socket instanceof SSLSocket)) {\n      throw new IOException(\n          \"SocketFactory \" + socketFactory + \" did not produce an SSLSocket: \" + socket.getClass());\n    }\n    SSLSocket sslSocket = (SSLSocket) socket;\n    sslSocket.setUseClientMode(false);\n    connectionSpec.apply(sslSocket, false);\n    Protocol expectedProtocol = Protocol.HTTP_2;\n    String negotiatedProtocol = OkHttpProtocolNegotiator.get().negotiate(\n        sslSocket,\n        null,\n        connectionSpec.supportsTlsExtensions() ? Arrays.asList(expectedProtocol) : null);\n    if (!expectedProtocol.toString().equals(negotiatedProtocol)) {\n      throw new IOException(\"Expected NPN/ALPN \" + expectedProtocol + \": \" + negotiatedProtocol);\n    }\n    attributes = result.attributes.toBuilder()\n        .set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)\n        .set(Grpc.TRANSPORT_ATTR_SSL_SESSION, sslSocket.getSession())\n        .build();\n    return new HandshakeResult(socket, attributes,\n        new InternalChannelz.Security(new InternalChannelz.Tls(sslSocket.getSession())));\n  }\n}\n","sourceCodeStart":45,"sourceCodeEnd":73,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/TlsServerHandshakerSocketFactory.java#L45-L73","documentation":"During the TLS server handshake, TlsServerHandshakerSocketFactory negotiates the application protocol via NPN/ALPN and requires it to be exactly h2 (Protocol.HTTP_2). If the client negotiated nothing or a different protocol, it throws IOException 'Expected NPN/ALPN h2: <negotiated>'.","triggerScenarios":"A client completes the TLS handshake without negotiating h2 — e.g. client without ALPN support, ALPN extension stripped by a middlebox/TLS terminator, or connectionSpec without TLS extensions.","commonSituations":"Old JDKs lacking ALPN (pre-JDK8u251/9+), proxies or load balancers terminating TLS and dropping ALPN, HTTP/1.1-only clients connecting to a gRPC server.","solutions":["Ensure clients use an HTTP/2-capable stack with ALPN support; upgrade JDK or use a JDK with built-in ALPN","Remove TLS-terminating intermediaries or configure them to pass through ALPN","Set the server's connection spec to include TLS extensions (supportsTlsExtensions) so negotiation happens","Confirm with openssl s_client -alpn h2 that h2 is negotiated end-to-end"],"exampleFix":"// before\nconnSpec = ConnectionSpec.MODERN_TLS; // may omit TLS extensions on some stacks\n// after\nconnSpec = ConnectionSpec.MODERN_TLS.toBuilder().supportsTlsExtensions(true).build();","handlingStrategy":"try-catch","validationCode":"// Check ALPN support on the current JVM\nboolean alpnOk = java.security.Security.getProperty(\"jdk.tls.alpnDisabledAlgorithms\") != null;","typeGuard":null,"tryCatchPattern":"try { result = factory.handshake(socket, attrs); }\ncatch (IOException e) {\n  if (e.getMessage().startsWith(\"Expected NPN/ALPN\")) { /* ensure client supports h2 ALPN or remove TLS terminator */ throw e; }\n}","preventionTips":["Use JDK 8u251+/11+ with built-in ALPN","Configure load balancers to pass through ALPN or terminate HTTP/2","Set connectionSpec with supportsTlsExtensions(true) and verify clients negotiate h2"],"tags":["grpc","java","alpn","http2","tls","handshake"],"backgroundTag":"alpn-negotiation-failure","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"}