Skip to content

[vite-plugin] Non-101 WebSocket upgrade responses are destroyed instead of delivered to the client in dev #15170

Description

@colinchadwick

What versions & operating system are you using?

System:
OS: macOS 26.5.2
CPU: (10) arm64 Apple M4
Memory: 114.05 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.12.0
npm: 11.6.2
bun: 1.3.14
npmPackages:
@cloudflare/vite-plugin: ^1.52.0 => 1.52.0
wrangler: ^4.122.0 => 4.122.0

Please provide a link to a minimal reproduction

https://github.com/colinchadwick/vite-plugin-ws-rejection-repro

Describe the Bug

In dev mode, when a Worker responds to a WebSocket upgrade request with a non-101 HTTP response (e.g. 401 to reject an unauthenticated upgrade), the client socket is destroyed without any HTTP response — the client never receives the status code. This breaks native WebSocket clients that rely on the status to distinguish "rejected — refresh and retry" from a network failure.

Rejecting a WebSocket upgrade with a normal HTTP status is the standard RFC 6455 mechanism. RFC 6455 §4.1:

If the status code received from the server is not 101, the client handles the response per HTTP [RFC2616] procedures. In particular, the client might perform authentication if it receives a 401 status code...

Steps to reproduce:

  1. npm install
  2. npm run dev
  3. npm run client (sends a WS upgrade request to a Worker that responds 401 without upgrading)

Expected — the Worker's 401 response is delivered on the upgrade request:

RECEIVED RESPONSE:
HTTP 401 Unauthorized
Content-Type: text/plain;charset=UTF-8
...
rejected: unauthorized

Actual — the connection is destroyed with no bytes delivered.

Root causepackages/vite-plugin-cloudflare/src/websockets.ts (handleWebSocket):

const workerWebSocket = response.webSocket;
if (!workerWebSocket) {
	socket.destroy();
	return;
}

There is no code path that writes a non-101 response back to the client; the relay only supports 101-with-webSocket or destroy.

Please provide any relevant error logs

CONNECTION DESTROYED, NO HTTP RESPONSE: socket hang up

Metadata

Metadata

Assignees

No one assigned

    Labels

    package:vite-pluginRelating to the `@cloudflare/vite-plugin` package

    Type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions