#15603: fix(gateway): correct malformed HTTP 429 response on WebSocket upgrade
gateway
stale
size: XS
Cluster:
Gateway Error Handling Improvements
## Summary
- `writeUpgradeAuthFailure` built the 429 response as an array joined by `\r\n`, with an empty string `""` as the header/body separator
- `.filter(Boolean)` removed the empty string since `Boolean("") === false`, producing a malformed HTTP response with no blank line between headers and body
- The 401 path on line 185 correctly used hardcoded `\r\n\r\n`
## Fix
- Build headers array separately (with `filter(Boolean)` for optional Retry-After), then join headers and body with the required `\r\n\r\n` separator
## Test plan
- [x] Existing gateway tests pass
- [x] Manual inspection confirms well-formed HTTP response structure
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes the HTTP response written directly to the raw socket when rejecting a WebSocket upgrade due to rate limiting.
Previously, the 429 response was assembled as an array joined by `\r\n`, relying on an empty string element as the required header/body separator. Because the array was then passed through `.filter(Boolean)`, the empty string separator was removed, producing a malformed HTTP response without the required blank line between headers and body.
The change builds the header block separately (still filtering out the optional `Retry-After` line), then concatenates headers and JSON body using the correct `\r\n\r\n` delimiter, matching the existing 401 upgrade-failure path.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is narrowly scoped to constructing a raw HTTP 429 response for WebSocket upgrade rejection and corrects a definite protocol formatting bug (missing CRLF-CRLF) without altering authentication or rate-limit logic. No additional code paths or dependencies were introduced.
- No files require special attention
<sub>Last reviewed commit: 6875525</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#11101: fix: handle AbortError and WebSocket 1006 in unhandled rejection ha...
by Nipurn123 · 2026-02-07
77.0%
#11740: fix(gateway): remove IP-based canvas auth fallback
by coygeek · 2026-02-08
76.4%
#23355: Gateway: fail closed on untrusted proxy headers
by bmendonca3 · 2026-02-22
76.0%
#6466: fix(gateway): add handshake timeout and connection error handling
by jarvis-raven · 2026-02-01
75.9%
#12314: fix: treat HTTP 5xx server errors as failover-worthy
by hsssgdtc · 2026-02-09
75.7%
#10745: feat: Security improvements and Windows compatibility fixes
by lluviaoscuradeldoce-design · 2026-02-06
75.4%
#21233: docs: clarify bind=lan non-loopback access requires wss or tunnel (...
by saurabhchopade · 2026-02-19
75.4%
#9178: Fix: GatewayClient queueConnect() setTimeout never fires
by vishaltandale00 · 2026-02-04
75.2%
#6302: fix: Add timeouts to prevent indefinite hangs (issues #4954, #4956,...
by batumilove · 2026-02-01
75.1%
#16994: fix(gateway): prevent double terminal SSE event on OpenResponses error
by AI-Reviewer-QS · 2026-02-15
75.0%