grpc/grpc-java · error · IOException
Expected NPN/ALPN ${expectedProtocol}: ${negotiatedProtocol}
Error message
Expected NPN/ALPN ${expectedProtocol}: ${negotiatedProtocol} What it means
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>'.
Source
Thrown at okhttp/src/main/java/io/grpc/okhttp/TlsServerHandshakerSocketFactory.java:63
@Override
public HandshakeResult handshake(Socket socket, Attributes attributes) throws IOException {
HandshakeResult result = delegate.handshake(socket, attributes);
socket = socketFactory.createSocket(result.socket, null, -1, true);
if (!(socket instanceof SSLSocket)) {
throw new IOException(
"SocketFactory " + socketFactory + " did not produce an SSLSocket: " + socket.getClass());
}
SSLSocket sslSocket = (SSLSocket) socket;
sslSocket.setUseClientMode(false);
connectionSpec.apply(sslSocket, false);
Protocol expectedProtocol = Protocol.HTTP_2;
String negotiatedProtocol = OkHttpProtocolNegotiator.get().negotiate(
sslSocket,
null,
connectionSpec.supportsTlsExtensions() ? Arrays.asList(expectedProtocol) : null);
if (!expectedProtocol.toString().equals(negotiatedProtocol)) {
throw new IOException("Expected NPN/ALPN " + expectedProtocol + ": " + negotiatedProtocol);
}
attributes = result.attributes.toBuilder()
.set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)
.set(Grpc.TRANSPORT_ATTR_SSL_SESSION, sslSocket.getSession())
.build();
return new HandshakeResult(socket, attributes,
new InternalChannelz.Security(new InternalChannelz.Tls(sslSocket.getSession())));
}
}
View on GitHub (pinned to 64daddc1f3)
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
Example fix
// before connSpec = ConnectionSpec.MODERN_TLS; // may omit TLS extensions on some stacks // after connSpec = ConnectionSpec.MODERN_TLS.toBuilder().supportsTlsExtensions(true).build();
Defensive patterns
Strategy: try-catch
Validate before calling
// Check ALPN support on the current JVM
boolean alpnOk = java.security.Security.getProperty("jdk.tls.alpnDisabledAlgorithms") != null; Try / catch
try { result = factory.handshake(socket, attrs); }
catch (IOException e) {
if (e.getMessage().startsWith("Expected NPN/ALPN")) { /* ensure client supports h2 ALPN or remove TLS terminator */ throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- TLS ALPN negotiation failed with protocols: ${protocols}
- SocketFactory ${socketFactory} did not produce an SSLSocket:
- Can't set TLS settings for ALTS
- Could not find Jetty NPN/ALPN or Conscrypt as installed JDK
- ${jdkProvider} selected, but Java 9+ and Jetty NPN/ALPN unav
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/67be5a35428be274.
Report an issue: GitHub.