ERR_CONNECTION_RESET / ECONNRESET (tested)
ERR_CONNECTION_RESET (Chrome) and ECONNRESET (Node.js) both mean the other side sent a TCP RST: it killed the connection instead of closing it politely. We triggered resets on purpose and wrote down what every client printed.
1. What a reset is
A TCP connection can end two ways. A FIN is a normal close: "I am done sending." A RST is an abort: "this connection is gone, drop everything." Clients report the two very differently. A reset can come from the server, or from anything in the middle: a proxy, a load balancer, a firewall, antivirus, or a VPN.
2. Our test server
We ran three tiny Node.js 24 servers on localhost. Each waits for the request bytes, then misbehaves:
const net = require('net');
function mk(port, fn) {
net.createServer(s => { s.once('data', () => fn(s)); s.on('error', () => {}); })
.listen(port, '127.0.0.1');
}
// A: RST before any response
mk(8993, s => s.resetAndDestroy());
// B: FIN before any response
mk(8994, s => s.destroy());
// C: headers + 1000 of 100000 body bytes, then RST
mk(8995, s => {
s.write('HTTP/1.1 200 OK\r\nContent-Length: 100000\r\n\r\n' + 'x'.repeat(1000));
setTimeout(() => s.resetAndDestroy(), 200);
});
socket.resetAndDestroy() sends a RST. socket.destroy() sends a FIN.
3. RST vs FIN before any response
| Client | RST (resetAndDestroy) | FIN (destroy) |
|---|---|---|
| Chromium 153 (page.goto) | net::ERR_CONNECTION_RESET | net::ERR_EMPTY_RESPONSE |
| curl 8.14.1 | curl: (56) Recv failure: Connection reset by peer | curl: (52) Empty reply from server |
| Node.js 24 fetch | TypeError: fetch failed, cause ECONNRESET (read ECONNRESET) | TypeError: fetch failed, cause UND_ERR_SOCKET (other side closed) |
| Python 3.13 urllib | ConnectionResetError: [Errno 104] Connection reset by peer | RemoteDisconnected: Remote end closed connection without response |
So the word "reset" only shows up for a real RST. If you see "empty reply" or "other side closed", the server closed cleanly without answering. That is a different bug, often a crash or a timeout in the app.
In Node.js, the useful part is in err.cause. The top-level message is just fetch failed in both cases. Log err.cause.code.
4. RST in the middle of the body
Server C sent a 200 status and headers, then 1000 of the promised 100000 bytes, then a RST.
| Client | What happened |
|---|---|
| Chromium 153 | Request failed with net::ERR_CONNECTION_RESET. page.goto did not return a response: once it said Navigation ... is interrupted by another navigation to "chrome-error://chromewebdata/", once it timed out. |
| curl 8.14.1 | curl: (56) Recv failure: Connection reset by peer (same code as before headers) |
| Node.js 24 fetch | fetch() resolved with status 200. Reading the body threw TypeError: terminated, cause ECONNRESET. |
| Python 3.13 urllib | urlopen() returned status 200. read() raised ConnectionResetError: [Errno 104] Connection reset by peer. |
The trap: in Node.js and Python, the status check passes. The error only appears when you read the body. Wrap the body read in your error handling and retry logic, not just the request.
5. The classic Node.js cause: keep-alive race
A very common ECONNRESET in Node.js services comes from connection reuse. The server closes an idle keep-alive connection at the same moment the client sends a new request on it. The client gets a reset or a closed socket. The fix is to make the server's idle timeout longer than the client's (or the load balancer's). We measured this in the Keep-Alive and Connection header guide. If a proxy sits between them, the same race shows up as a 502 Bad Gateway.
6. Server closing on a too-large request
Some servers and proxies give up on a request that is too big and close the connection instead of sending a full error response. Then the client sees a reset where you expected a status code. Check request size limits: see 431 Request Header Fields Too Large for big headers or cookies, and 413 Request Entity Too Large for big uploads.
7. Causes outside your code (not tested)
These come from vendor docs and common troubleshooting, not from our run:
- Antivirus or firewall with HTTPS or web scanning can reset connections it does not like. Try disabling it for one test.
- VPN or corporate proxy can reset connections to blocked hosts. Try without it, or from another network.
- Windows network stack: Microsoft documents
netsh winsock reset(run as admin, then reboot) to reset Winsock settings that third-party software may have changed. - MTU problems: small requests work, large ones hang or reset, often on VPNs or PPPoE links.
- ISP or national filtering can inject resets for certain sites. Changing network is the quick test.
8. How to narrow it down
- Run
curl -vagainst the same URL. Exit 56 means reset; exit 52 means clean close with no reply. - Try from another network. If the error goes away, look at the network path, not the server.
- Hit the server directly, skipping the proxy or CDN. If that works, the proxy is the one resetting.
- Check server logs at the exact time. A crash, a timeout, or a size limit usually shows up there.
Frequently asked questions
What is the difference between ERR_CONNECTION_RESET and ERR_EMPTY_RESPONSE?
In our test, Chromium showed ERR_CONNECTION_RESET when the server sent a TCP RST, and ERR_EMPTY_RESPONSE when the server closed normally (FIN) without sending anything. curl showed exit 56 and exit 52 for the same two cases.
Why does Node.js fetch just say 'fetch failed'?
The real reason is in err.cause. For a reset we saw cause code ECONNRESET with message 'read ECONNRESET'. For a clean close it was UND_ERR_SOCKET with 'other side closed'. Log err.cause.code.
Can I get a 200 status and still get ECONNRESET?
Yes. When the server reset after sending headers, Node.js fetch and Python urllib both returned status 200. The error came only when reading the body: 'TypeError: terminated' (cause ECONNRESET) in Node.js and ConnectionResetError in Python.
What is the most common cause of ECONNRESET in Node.js servers?
A keep-alive race: the server closes an idle connection just as the client reuses it. Make the server's keepAliveTimeout longer than the client's or load balancer's idle timeout. See our Keep-Alive guide.
Does netsh winsock reset fix ERR_CONNECTION_RESET?
Sometimes, on Windows, when other software has changed network settings. We did not test it. Try it after ruling out antivirus, VPN and proxy, and after checking the site works from another device.
Written with AI assistance. Measured on 2026-10-02 with headless Chromium 153 (Playwright 1.63), curl 8.14.1, Node.js 24.21.0 fetch and Python 3.13.5 urllib against a tiny Node.js server that sent a TCP RST (socket.resetAndDestroy()) or a plain FIN (socket.destroy()). PlainHeaders is our extension; Chromium, curl, Node.js and Python are free.