eclipse-vertx/vert.x · error · WebSocketHandshakeException

Invalid WebSocket version

Error message

Invalid WebSocket version

What it means

This WebSocketHandshakeException is thrown in createHandshaker when the client requests an unsupported WebSocket sub-version in the Sec-WebSocket-Version header (only version 13 is supported). Vert.x responds with 426/Upgrade Required and includes a Sec-WebSocket-Version header advertising version 13.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java:412

      subProtocols = String.join(",", webSocketConfig.getSubProtocols());
    }
    WebSocketDecoderConfig config = WebSocketDecoderConfig.newBuilder()
      .allowExtensions(webSocketConfig.getUsePerMessageCompression() || webSocketConfig.getUsePerFrameCompression())
      .maxFramePayloadLength(webSocketConfig.getMaxFrameSize())
      .allowMaskMismatch(webSocketConfig.isUseUnmaskedFrames())
      .closeOnProtocolViolation(false)
      .build();
    WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(wsURL, subProtocols, config);
    WebSocketServerHandshaker shake = factory.newHandshaker(request.nettyRequest());
    if (shake != null) {
      return shake;
    }
    // See WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ch);
    request.response()
      .putHeader(HttpHeaderNames.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue())
      .setStatusCode(UPGRADE_REQUIRED.code())
      .end();
    throw new WebSocketHandshakeException("Invalid WebSocket version");
  }

  public void netSocket(Handler<AsyncResult<NetSocket>> handler) {
    Future<NetSocket> fut = netSocket();
    if (handler != null) {
      fut.onComplete(handler);
    }
  }

  public Future<NetSocket> netSocket() {
    Promise<NetSocket> promise = context.promise();
    netSocket(promise);
    return promise.future();
  }

  void netSocket(Promise<NetSocket> promise) {
    context.execute(() -> {

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Update the client to send Sec-WebSocket-Version: 13 (or omit it; modern libraries default to 13).
  2. Upgrade the legacy WebSocket client library to an RFC 6455-compliant one.
  3. Handle the 426 Upgrade Required response on the client and retry with version 13 as advertised in the response's Sec-WebSocket-Version header.
  4. For genuinely legacy clients, place a translation layer/gateway that rewrites the handshake to version 13.

Example fix

// before (client)
request.putHeader("Sec-WebSocket-Version", "8");

// after
request.putHeader("Sec-WebSocket-Version", "13");
Defensive patterns

Strategy: validation

Validate before calling

String ver = request.getHeader(HttpHeaders.SEC_WEBSOCKET_VERSION);
if (ver == null || !"13".equals(ver.trim())) {
  // send 426 with Sec-WebSocket-Version: 13
}

Try / catch

try {
  serverRequest.toWebSocket();
} catch (WebSocketHandshakeException e) {
  respondUpgradeRequired();
}

Prevention

When it happens

Trigger: Client sends Sec-WebSocket-Version: 8 (Hixie-76/hybi-00 era clients), 7, or any value other than 13 during the WebSocket upgrade, and the server then calls the upgrade path (createHandshaker from createWebSocket).

Common situations: Very old browsers or legacy WebSocket client libraries (pre-RFC6455 draft versions); hand-rolled clients hardcoding an outdated version header; older corporate tooling behind the upgrade endpoint.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/eb80af799f7963d1. Report an issue: GitHub.