Skip to content

fix: drop the companion WebSocket subprotocol entirely#41

Merged
Anton-Horn merged 1 commit into
mainfrom
fix/companion-drop-ws-subprotocol
Jun 3, 2026
Merged

fix: drop the companion WebSocket subprotocol entirely#41
Anton-Horn merged 1 commit into
mainfrom
fix/companion-drop-ws-subprotocol

Conversation

@Anton-Horn
Copy link
Copy Markdown
Contributor

Problem

On the deployed reverse proxy, the companion /ws/companion socket dies <1s after the handshake and loops connect→disconnect (retrying every 30s once backoff maxes out). Production logs (via ocd 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 /ws stays connected through the same proxy for the same user. The difference: chat uses no subprotocol (cookie/query token), the companion offered a Sec-WebSocket-Protocol: zero-companion subprotocol. Reverse proxies commonly mishandle the subprotocol echo (this same mechanism also caused the earlier 1002 "Mismatch client protocol" on some Bun versions).

Fix

The subprotocol was already vestigial — since the token moved to the x-zero-companion-token request header (PR #39), zero-companion carried no information. Connect with an empty protocols array so there's no Sec-WebSocket-Protocol for 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

  • Verified under Bun: new WebSocket(url, [], { headers }) sends no Sec-WebSocket-Protocol, the token rides in the header, and the connection opens and stays up.
  • bunx tsc --noEmit clean; CLI bundle rebuilt.

Deploy

Server can deploy anytime (backward compatible). Reinstall the CLI on the laptop (curl … | sh) so it runs the new bundle, then zero browser connect should hold the link.

🤖 Generated with Claude Code

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).
@Anton-Horn Anton-Horn merged commit 3e7e930 into main Jun 3, 2026
2 checks passed
@Anton-Horn Anton-Horn deleted the fix/companion-drop-ws-subprotocol branch June 3, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant