eclipse-vertx/vert.x · error · WebSocketHandshakeException
Invalid connection header
Error message
Invalid connection header
What it means
This WebSocketHandshakeException is thrown in createHandshaker when a WebSocket upgrade request lacks a "Connection" header containing "Upgrade". The HTTP/1.1 upgrade handshake requires both "Connection: Upgrade" and "Upgrade: websocket" headers. Vert.x rejects the request with a 400 response before the handshaker is created.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java:375
} catch (WebSocketHandshakeException e) {
promise.fail(e);
return;
}
promise.complete(new ServerWebSocketHandshaker(request, handshaker, webSocketConfig, registerWebSocketWriteHandlers));
}
});
}
public WebSocketServerHandshaker createHandshaker(Http1ServerRequest request) throws WebSocketHandshakeException {
// As a fun part, Firefox 6.0.2 supports Websockets protocol '7'. But,
// it doesn't send a normal 'Connection: Upgrade' header. Instead it
// sends: 'Connection: keep-alive, Upgrade'. Brilliant.
String connectionHeader = request.getHeader(io.vertx.core.http.HttpHeaders.CONNECTION);
if (connectionHeader == null || !connectionHeader.toLowerCase().contains("upgrade")) {
request.response()
.setStatusCode(BAD_REQUEST.code())
.end("\"Connection\" header must be \"Upgrade\".");
throw new WebSocketHandshakeException("Invalid connection header");
}
if (request.method() != io.vertx.core.http.HttpMethod.GET) {
request.response()
.setStatusCode(METHOD_NOT_ALLOWED.code())
.end();
throw new WebSocketHandshakeException("Invalid HTTP method");
}
String wsURL;
try {
wsURL = HttpUtils.getWebSocketLocation(request, isSsl());
} catch (Exception e) {
request.response()
.setStatusCode(BAD_REQUEST.code())
.end("Invalid request URI");
throw new WebSocketHandshakeException("Invalid WebSocket location", e);
}
String subProtocols = null;
if (webSocketConfig.getSubProtocols() != null) {View on GitHub (pinned to fb308bd8c3)
Solutions
- Ensure the client sends "Connection: Upgrade" and "Upgrade: websocket" headers with the GET request.
- If a proxy sits in front, configure it to forward the Connection and Upgrade headers (e.g. nginx proxy_set_header Connection $connection_upgrade).
- Inspect the actual incoming headers (request.headers()) to confirm what the client sent before upgrading.
- Return a clear 400 to the client when the handshake fails so the client-side code can surface the misconfiguration.
Example fix
// before (client-side)
request.putHeader("Upgrade", "websocket");
// after
request.putHeader("Upgrade", "websocket");
request.putHeader("Connection", "Upgrade"); Defensive patterns
Strategy: validation
Validate before calling
String conn = request.getHeader(HttpHeaders.CONNECTION);
if (conn == null || !conn.toLowerCase().contains("upgrade")) {
// reject before upgrade
} Try / catch
try {
serverRequest.toWebSocket();
} catch (WebSocketHandshakeException e) {
log.warn("Bad upgrade request: " + e.getMessage());
} Prevention
- Always send "Connection: Upgrade" and "Upgrade: websocket" on handshake
- Verify proxies forward hop-by-hop upgrade headers
- Test handshake endpoints with a real WebSocket client, not plain curl
When it happens
Trigger: Calling server upgrade methods (upgrade/createWebSocket path) with an incoming request whose Connection header is missing or does not contain "upgrade" (case-insensitive check), e.g. "Connection: keep-alive" only.
Common situations: Hand-rolled WebSocket clients forgetting the Connection header; proxies or intermediaries stripping or rewriting the Connection header; testing the upgrade endpoint with curl or a plain GET that lacks proper upgrade headers.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Invalid HTTP method
- Invalid WebSocket location
- Invalid WebSocket version
- Protocol version ${version} not supported.
- Response head already sent
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/db5b85fe5b9b95dd.
Report an issue: GitHub.