Uh oh!
There was an error while loading. Please reload this page.
fix(fetch): do not crash on late EPIPE after refused body - #42116
Conversation
When a server answers without reading the request body and then resets the socket, Node can emit a late write EPIPE/ECONNRESET on the client socket. APIRequestContext does not listen for that, so the process dies. Fixes: microsoft#42074 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hi, I'm the Playwright bot and I took a first look at the CI failures here. 🔴 The failures are caused by this PR — by designEight of the nine failures are the new DetailsCaused by this PR
Pre-existing flake / infra
Triaged by the Playwright bot - agent run |
Listen for errors on the request socket and ignore network write errors once response headers have arrived, matching undici policy. Otherwise a server that answers (e.g. 413) without reading the body can leave an unhandled socket EPIPE/ECONNRESET and kill the process. Fixes: microsoft#42074 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Remove the per-request socket error handler when the request closes and the socket is still alive, so keep-alive reuse does not accumulate listeners. If the socket is already destroyed, leave the handler for a possible late write EPIPE. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| socket.on('error', handleRequestError); | ||
| request.once('close', () => { | ||
| if (!socket.destroyed) |
There was a problem hiding this comment.
Add a comment explaining why it has to be removed and only if !socket.destroyed.
There was a problem hiding this comment.
Done in 4d0640d - kept the destroy check and documented why.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cd1c251-bdcb-4f5f-b9a6-17ed643d095e
Uh oh!
There was an error while loading. Please reload this page.
Test results for "tests 1"7 flaky51230 passed, 1190 skipped Merge workflow run. |
Test results for "MCP"3 failed 8047 passed, 1284 skipped Merge workflow run. |
Hi, I'm the Playwright bot and I took a first look at the CI failures here. 🟢 CI is clear — all three failures are pre-existing flakesThe latest report (MCP run) has three failures, and none of them touch this PR's change. The diff only edits DetailsThe diff changes late- Pre-existing flake / infra
Of 56 failing runs for these three tests across the whole DB, only 3 are on this PR (one per test) — the rest are spread across dozens of other PRs. That's a flake fingerprint, not a regression. For completeness: the earlier "tests 1" reports on this PR came back with only flaky (retry-rescued) results, no hard failures. The new Triaged by the Playwright bot Triaged by the Playwright bot - agent run |
Fixes#42074.
node:httphas a footgun wheresocket.on('error')is bubbled up intorequest.on('error')while the request is ongoing. If the server decides not to read the request body in full, e.g. to prevent DoS, there is a race where it first responds413, fulfilling the response and unlinkingsocket.on('error')fromrequest.on('error'), and only after that the client receives an error while trying to finish writing its request body. This is an unhandled error event and crashes the host process.The fix is to listen for the
errorevent and swallow it if the race was detected. Axios fixed this race in axios/axios#10576, i'm looking into whatgotdoes now.