TooTallNate/Java-WebSocket · error · InvalidHandshakeException
missing Sec-WebSocket-Key
Error message
missing Sec-WebSocket-Key
What it means
When acting as a server, Draft_6455 must include the Sec-WebSocket-Accept header in the 101 response, computed from the client's Sec-WebSocket-Key per RFC 6455. If the incoming client handshake lacks a Sec-WebSocket-Key header (empty or missing), postProcessHandshakeResponseAsServer throws this InvalidHandshakeException and the upgrade fails.
Solutions
- Make the connecting client send Sec-WebSocket-Key (any real RFC 6455 client library does)
- Exclude the WebSocket port from health-check probes or configure a TCP-level check instead
- If writing a raw client, include "Sec-WebSocket-Key: <base64 16-byte value>" in the request
- Log the offending client handshake to identify the non-conformant source
Example fix
// before (raw client request)
output.write("GET /ws HTTP/1.1\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n");
// after
output.write("GET /ws HTTP/1.1\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"); Defensive patterns
Strategy: try-catch
Validate before calling
// before accepting an upgrade as server, verify the client sent the key
String key = request.getFieldValue("Sec-WebSocket-Key");
if (key == null || key.isEmpty()) {
// reject/hand off: not a valid RFC 6455 client
return AbortHandshake.forInvalidRequestCode(400);
} Try / catch
public ServerHandshakeBuilder onWebsocketHandshakeReceivedAsServer(WebSocket conn, Draft draft, ClientHandshake request) throws InvalidHandshakeException {
if (request.getFieldValue("Sec-WebSocket-Key").isEmpty())
throw new InvalidHandshakeException("not a WebSocket client");
return super.onWebsocketHandshakeReceivedAsServer(conn, draft, request);
} Prevention
- Exclude the WS port from plain HTTP health checks
- Use real RFC 6455 client libraries
- Log offending handshakes to identify probes and broken clients
When it happens
Trigger: A client connects without sending the Sec-WebSocket-Key header — e.g. a hand-rolled HTTP client, a health check or plain HTTP probe hitting the WS port, or a very old/non-conformant WebSocket client.
Common situations: Load balancer health checks port-scanning the WebSocket server, custom client code forgetting the required handshake headers, tools sending plain HTTP requests to the WS endpoint.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Invalid status code received
- unknown role
- http resource descriptor must not be null
- buffer size < 0
- parameter must not be null
AI-assisted analysis of TooTallNate/Java-WebSocket@afeacbf8c0 (2026-09-09).
Data as JSON: /api/errors/41dc4551b1e3631a.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/org/java_websocket/drafts/Draft_6455.java:439
}
requestedProtocols.append(knownProtocol.getProvidedProtocol());
}
}
if (requestedProtocols.length() != 0) {
request.put(SEC_WEB_SOCKET_PROTOCOL, requestedProtocols.toString());
}
return request;
}
@Override
public HandshakeBuilder postProcessHandshakeResponseAsServer(ClientHandshake request,
ServerHandshakeBuilder response) throws InvalidHandshakeException {
response.put(UPGRADE, "websocket");
response.put(CONNECTION,
request.getFieldValue(CONNECTION)); // to respond to a Connection keep alives
String seckey = request.getFieldValue(SEC_WEB_SOCKET_KEY);
if (seckey == null || "".equals(seckey)) {
throw new InvalidHandshakeException("missing Sec-WebSocket-Key");
}
response.put(SEC_WEB_SOCKET_ACCEPT, generateFinalKey(seckey));
if (getExtension().getProvidedExtensionAsServer().length() != 0) {
response.put(SEC_WEB_SOCKET_EXTENSIONS, getExtension().getProvidedExtensionAsServer());
}
if (getProtocol() != null && getProtocol().getProvidedProtocol().length() != 0) {
response.put(SEC_WEB_SOCKET_PROTOCOL, getProtocol().getProvidedProtocol());
}
response.setHttpStatusMessage("Web Socket Protocol Handshake");
response.put("Server", "TooTallNate Java-WebSocket");
response.put("Date", getServerTime());
return response;
}
@Override
public Draft copyInstance() {
ArrayList<IExtension> newExtensions = new ArrayList<>();
for (IExtension knownExtension : getKnownExtensions()) {View on GitHub (pinned to afeacbf8c0)