fix: drop the companion WebSocket subprotocol entirely#41
Merged
Conversation
The companion `/ws/companion` socket was dying <1s after the handshake on a deployed reverse proxy, looping connect→disconnect, while the chat `/ws` (no subprotocol, cookie/query token) stayed up through the same proxy. Server logs showed the upgrade completing then the socket closing with no app-side teardown — the proxy mishandling the `Sec-WebSocket-Protocol` echo. The subprotocol was already vestigial: since the token moved to the `x-zero-companion-token` request header, `zero-companion` carried no information and the server authenticates off the header. Connect with an empty protocols array so there's no subprotocol to echo — mirroring the chat socket that works. No server change needed (it already reads the header, with the old subprotocol kept only as a fallback for older clients).
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.
Problem
On the deployed reverse proxy, the companion
/ws/companionsocket dies <1s after the handshake and loops connect→disconnect (retrying every 30s once backoff maxes out). Production logs (viaocd logs zero-server) show the upgrade completing —companion connected— then the socket closing immediately with no app-side teardown (no eviction, no liveness termination, no socket error).Meanwhile the chat
/wsstays connected through the same proxy for the same user. The difference: chat uses no subprotocol (cookie/query token), the companion offered aSec-WebSocket-Protocol: zero-companionsubprotocol. Reverse proxies commonly mishandle the subprotocol echo (this same mechanism also caused the earlier1002 "Mismatch client protocol"on some Bun versions).Fix
The subprotocol was already vestigial — since the token moved to the
x-zero-companion-tokenrequest header (PR #39),zero-companioncarried no information. Connect with an empty protocols array so there's noSec-WebSocket-Protocolfor a proxy to mangle, mirroring the chat socket that works.No server change: it already authenticates off the header, keeping the old subprotocol only as a fallback for not-yet-updated clients.
Testing
new WebSocket(url, [], { headers })sends noSec-WebSocket-Protocol, the token rides in the header, and the connection opens and stays up.bunx tsc --noEmitclean; CLI bundle rebuilt.Deploy
Server can deploy anytime (backward compatible). Reinstall the CLI on the laptop (
curl … | sh) so it runs the new bundle, thenzero browser connectshould hold the link.🤖 Generated with Claude Code