fix(proxy): missing proxyRes error handler + SSE corruption on error after headers#18
Draft
aattaran wants to merge 1 commit into
Draft
fix(proxy): missing proxyRes error handler + SSE corruption on error after headers#18aattaran wants to merge 1 commit into
aattaran wants to merge 1 commit into
Conversation
…proxyReq error after headers
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
Two production bugs in
proxy/model-proxy.jssurfaced by an audit run againstaattaran/Jarvis2(shared proxy ancestry — both fixes apply verbatim).Bug 1 — missing
proxyReserror handler (process crash)The three response paths inside the
httpsRequestcallback —proxyRes.pipe(norm).pipe(clientRes)(SSE)data/endJSON collectorproxyRes.pipe(clientRes)— never attach an
'error'handler toproxyRes. If the upstream connection drops mid-response (TCP RST, TLS abort, server crash), Node emits an unhandled'error'on the response stream and the entire proxy process exits, killing every concurrent in-flight Claude Code session.Fix: attach a single
proxyRes.on('error', ...)immediately after the response is opened, before any of the branch-specific piping. Mirrors the existingproxyReq.on('error')shape: 502+JSON if headers haven't gone out, otherwise destroy the response.Bug 2 — SSE corruption when
proxyReqerrors after headers sentCurrent
proxyReq.on('error')unconditionally calls:If headers already went out as
text/event-stream(the common SSE case for/v1/messages), that JSON gets injected mid-stream. Claude Code's SSE parser then sees a non-event payload and either silently truncates the assistant turn or throws — depending on where in the stream the upstream died.Fix:
clientRes.destroy(err)onceclientRes.headersSentis true, so the client sees a clean transport-level abort instead of a corrupted event stream.Files
proxy/model-proxy.js— addedproxyReserror handler; gatedproxyReqerror handler'send()on!headersSent.Note on the third audit finding
The same audit also flagged the
/_proxy/modeOrigin-prefix CSRF/DNS-rebinding issue. That's already covered by PR #16 (open, fromaaronjmars), so it is intentionally not in this PR.Test plan
iptables -A OUTPUT -p tcp --dport 443 -j REJECTafter first chunk) → before patch: process crashes / SSE garbage; after patch: clean client error, proxy survives./v1/messagesstill flow throughUsageNormalizerand produce correct/_proxy/cost./_proxy/status,/_proxy/mode,/_proxy/coststill respond correctly.Generated by Claude Code