eclipse-vertx/vert.x · error · WebSocketHandshakeException

Invalid HTTP method

Error message

Invalid HTTP method

What it means

This WebSocketHandshakeException is thrown in createHandshaker when the WebSocket upgrade request uses an HTTP method other than GET. RFC 6455 mandates that the opening handshake be a GET request. Vert.x responds with 405 Method Not Allowed and aborts the handshake.

Source

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

    });
  }

  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) {
      subProtocols = String.join(",", webSocketConfig.getSubProtocols());
    }
    WebSocketDecoderConfig config = WebSocketDecoderConfig.newBuilder()
      .allowExtensions(webSocketConfig.getUsePerMessageCompression() || webSocketConfig.getUsePerFrameCompression())
      .maxFramePayloadLength(webSocketConfig.getMaxFrameSize())
      .allowMaskMismatch(webSocketConfig.isUseUnmaskedFrames())

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Send the WebSocket handshake as an HTTP GET request.
  2. Fix client library configuration that overrides the handshake method.
  3. Route non-GET traffic away from the WebSocket endpoint so it never reaches the upgrade handler.
  4. If you need both REST and WebSocket on one URL, branch on request.method() before upgrading.

Example fix

// before
httpClient.request(HttpMethod.POST, "/ws")
  .compose(req -> req.send());

// after (WebSocket handshake must be GET)
client.webSocket("/ws");
Defensive patterns

Strategy: validation

Validate before calling

if (request.method() != HttpMethod.GET) {
  // WebSocket handshake must be GET; reject early
}

Try / catch

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

Prevention

When it happens

Trigger: Issuing POST/PUT/DELETE (or any non-GET) request to a WebSocket endpoint and then calling the server-side upgrade path (createHandshaker, invoked from createWebSocket).

Common situations: Posting JSON to a URL that also serves WebSocket upgrades; misconfigured client libraries using POST; load tests sending POST requests to a websocket route.

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


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