fix(vite-plugin): deliver non-101 responses on rejected WebSocket upgrades - #15205
Open
patrickswedish wants to merge 1 commit into
Open
fix(vite-plugin): deliver non-101 responses on rejected WebSocket upgrades#15205patrickswedish wants to merge 1 commit into
patrickswedish wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 2df0107 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
workers-devprod
requested review from
a team and
edmundhung
and removed request for
a team
August 15, 2026 10:03
Contributor
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
@cloudflare/autoconfig
@cloudflare/build-output-utils
@cloudflare/codemods
@cloudflare/config
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-functions
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-plugin
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
edmundhung
reviewed
Aug 20, 2026
edmundhung
left a comment
Member
There was a problem hiding this comment.
The comment from Devin looks valid. Can you take a look? I think the CI error also looks legit.
Contributor
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
Author
|
Thanks @edmundhung! That review observation was spot on. Summary of Fix
|
patrickswedish
force-pushed
the
fix/vite-plugin-ws-rejection-response
branch
from
August 29, 2026 13:40
74003c1 to
519c031
Compare
Contributor
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
…rades Fix WebSocket upgrade handling in Vite plugin dev mode so non-101 HTTP responses (such as 401 Unauthorized or 403 Forbidden) returned by Workers are properly written to the raw socket with backpressure and stream cleanup before terminating, rather than abruptly destroying the socket. Fixes cloudflare#15170
patrickswedish
force-pushed
the
fix/vite-plugin-ws-rejection-response
branch
from
August 30, 2026 14:27
519c031 to
2df0107
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #15170.
When a Worker rejects a WebSocket upgrade request with a non-101 HTTP response (such as
401 Unauthorizedor403 Forbidden), the Vite dev server'shandleWebSocketlistener previously sawresponse.webSocket === undefinedand calledsocket.destroy()unconditionally. This dropped the underlying socket without transmitting any HTTP response line, headers, or body, violating RFC 6455 §4.1 and causing native WebSocket clients to fail with abrupt socket hang-ups rather than handling the authentication challenge.Root Cause
In
packages/vite-plugin-cloudflare/src/websockets.ts(handleWebSocket), the upgrade listener only implemented the 101 WebSocket upgrade path. Non-101 responses were treated as unhandled failures and destroyed the socket directly:What Changed
!workerWebSocket, serialize the Worker'sResponsedirectly to the raw upgrade socket via dedicatedwriteHttpResponse().Set-Cookiesupport). DefaultsConnection: closeif not specified.waitForSocketDrain(), which resolves ondrain,close, orerrorevents to prevent unbounded buffering or indefinite hangs if remote peers disconnect.drain/close/errorand releases reader locks in afinallyblock (reader.releaseLock()).socket.end()rather than unconditionally invokingsocket.destroy().packages/vite-plugin-cloudflare/src/__tests__/websockets.spec.tstesting non-101 responses (401/403/etc.), header forwarding, body streaming, backpressure handling, client disconnect resilience, and listener cleanup.@cloudflare/vite-plugin.Validation
Tests included/updated
Documentation not necessary because: bug fix restoring standard RFC 6455 behavior in dev server
Tested with Vitest in
packages/vite-plugin-cloudflare(websockets.spec.ts).Verified 401/403 status, custom headers (
X-Custom-Auth), and body delivery on WebSocket upgrade rejections.Verified backpressure handling and client disconnect resilience without hanging workers or unhandled rejections.
Verified successful 101 WebSocket upgrades continue to work with header forwarding.
Compatibility / Risk
Zero risk to production runtime (this code only runs in
@cloudflare/vite-pluginlocal dev mode). Non-101 upgrade responses now adhere to standard RFC 6455 §4.1 behavior.