Skip to content

fix: read the request body before closing a response (v2.3.1) - #18

Merged
niqibiao merged 1 commit into
mainfrom
fix/health-response-reset
Aug 23, 2026
Merged

niqibiao merged 1 commit into
mainfrom
fix/health-response-reset

Conversation

@niqibiao

Copy link
Copy Markdown
Owner

The defect

/health builds its answer and writes it without ever reading the request body
the client sent. Windows tears down a response closed over an unread request
body with RST instead of FIN, so the answer was written and the caller saw a
dropped connection — WinError 10054 — about one call in five.

The service logged nothing, because from its side the request had been served.

Evidence

failures
/health with a body (what the client sends) 7/40
/health with an empty body 0/40
/command — a route that reads its body — with a body 0/40

Only health was affected, because it is the only route that never consumes
what it was sent. Measured at 8/40 against a player and 2/40 against an editor.

Three other explanations were ruled out first: the failures return in 15ms so
they are not queueing behind the serial dispatch loop; request spacing from 0ms
to 300ms does not change the rate, so it is not a burst effect; and
runInBackground was already on.

The fix

Drain the body in WriteEnvelopeResponseAsync, the writer every route shares.
That covers the 404/415 error responses too, where a reset would otherwise hide
the status code that explains what went wrong.

Verified

0/40 and 0/60 against an editor, 0/40 twice against a rebuilt IL2CPP player,
and 40/40 through cs health where the same run previously lost calls.
cs doctor and cs wait-ready probe through health, so both stop failing at
random too.

🤖 Generated with Claude Code

/health answered without ever reading the body the client sent, and
Windows tears down a response closed over an unread request body with
RST instead of FIN. The answer was written and the caller saw a dropped
connection: 8 failures in 40 calls against a player, 2 in 40 against an
editor, 0 in 40 once the body is drained first. The service logged
nothing, because from its side the request had been served.

Draining in the shared envelope writer covers the error responses too,
where a reset would otherwise hide the status code that explains the
failure. Every route that reads its own body was never affected, which
is why only health showed it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@niqibiao
niqibiao merged commit f154b18 into main Aug 23, 2026
1 check passed
@niqibiao
niqibiao deleted the fix/health-response-reset branch August 23, 2026 16:28
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