The Error
You're making an HTTP or HTTPS request and Node.js throws this:
Error: read ECONNRESET
at TLSSocket.onConnectEnd (_tls_wrap.js:1495:19)
at Object.onceWrapper (events.js:422:26)
at TLSSocket.emit (events.js:327:22)
The request dies mid-flight โ no status code, no response body, just a broken socket. It hits axios, the built-in https module, node-fetch, and anything else sitting on top of Node's socket layer.
What's Actually Happening
ECONNRESET means the remote server closed the TCP connection unexpectedly โ it sent a RST (reset) packet instead of a proper FIN. From Node's perspective, the connection was alive and then suddenly gone.
Several things can trigger this:
- The server has a short idle timeout and your connection sat in a keep-alive pool too long
- A reverse proxy (nginx, AWS ALB, Cloudflare) closed the connection before Node finished reading
- The server is under load and actively dropping connections
- A firewall or NAT device killed an idle socket
- You're reusing a socket from a connection pool that the server already closed
- TLS handshake failed mid-stream (less common, but happens with misconfigured certs)
Fix 1: Add Retry Logic
ECONNRESET is usually transient โ a single retry fixes it most of the time. Here's a simple retry wrapper for axios:
const axios = require('axios');
async function requestWithRetry(url, options = {}, retries = 3) {
for (let attempt = 1; attempt setTimeout(r, delay));
continue;
}
throw err;
}
}
}
// Usage
requestWithRetry('https://api.example.com/data')
.then(res => console.log(res.data))
.catch(err => console.error('All retries failed:', err.message));
Prefer a library? axios-retry handles this cleanly:
npm install axios-retry
const axios = require('axios');
const axiosRetry = require('axios-retry').default;
axiosRetry(axios, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
return axiosRetry.isNetworkError(error) || error.code === 'ECONNRESET';
},
});
Fix 2: Disable or Tune Keep-Alive
Node's HTTP agent reuses sockets across requests. The problem: the server may have already closed that socket by the time your next request arrives. You can either kill keep-alive entirely or set a socket timeout that's shorter than the server's idle timeout.
Option A โ Disable keep-alive (quickest fix)
const https = require('https');
const axios = require('axios');
const agent = new https.Agent({ keepAlive: false });
const client = axios.create({ httpsAgent: agent });
client.get('https://api.example.com/data')
.then(res => console.log(res.data));
Option B โ Keep keep-alive but set a shorter socket timeout
const https = require('https');
const axios = require('axios');
// Most servers close idle connections after 60โ120s.
// Set our timeout to 45s to recycle before the server does.
const agent = new https.Agent({
keepAlive: true,
timeout: 45000, // ms โ socket idle timeout
maxSockets: 10,
});
const client = axios.create({
httpsAgent: agent,
timeout: 30000, // request timeout
});
Fix 3: Set a Request Timeout
A hanging process is worse than a crashed one. Without a timeout, a reset socket can stall your app indefinitely. Always set one:
// axios
const client = axios.create({ timeout: 10000 }); // 10 seconds
// Built-in https module
const req = https.request(options, (res) => { /* ... */ });
req.setTimeout(10000, () => {
req.destroy(new Error('Request timed out'));
});
req.on('error', (err) => console.error(err.message));
Fix 4: Handle the Error Event on Raw Sockets
Raw http/https requests that throw ECONNRESET will crash your process if no error listener is attached. Node treats unhandled 'error' events as fatal. Fix it like this:
const https = require('https');
const req = https.request('https://api.example.com/data', (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => console.log(body));
});
req.on('error', (err) => {
// Without this, ECONNRESET = unhandled exception = crash
console.error('Request error:', err.code, err.message);
});
req.end();
Fix 5: Check for Proxy or Load Balancer Timeouts
Apps behind a load balancer face an extra wrinkle. AWS ALB, nginx, and similar proxies each have their own idle timeout โ ALB defaults to 60 seconds. When the proxy drops the connection, your Node app sees an ECONNRESET.
For AWS ALB, bump the idle timeout in the console: EC2 โ Load Balancers โ Attributes โ Idle timeout. Or keep your keep-alive socket timeout under 60s as shown in Fix 2.
For nginx acting as a reverse proxy:
# nginx.conf
proxy_read_timeout 120s;
proxy_send_timeout 120s;
keepalive_timeout 75s;
Verify the Fix
- Add a log line in your catch block:
console.log('err.code:', err.code). After the fix, you should stop seeingECONNRESET. - Run your request in a loop for 30โ60 seconds to confirm sockets are being recycled cleanly:
setInterval(() => {
client.get('https://api.example.com/ping')
.then(() => console.log('OK'))
.catch(err => console.error(err.code));
}, 5000);
- Watch
netstatorssto confirm no lingering sockets inCLOSE_WAIT:
watch -n 2 'ss -tan | grep CLOSE_WAIT | wc -l'
Tips
- Log the right fields: Always capture
err.code,err.address, anderr.portโ they tell you exactly which host reset the connection, which saves a lot of guessing. - Network debugging: If you suspect the issue is subnet routing or firewall rules between your Node app and the target server, ToolCraft's Subnet Calculator helps verify CIDR ranges and network addresses quickly โ handy when your app runs inside a VPC or corporate network.
- TLS issues: ECONNRESET on HTTPS only? Check for expired or self-signed certificates. Run
NODE_TLS_REJECT_UNAUTHORIZED=0temporarily (never in production) to confirm TLS is the culprit. - Concurrency: High
maxSocketscan overwhelm the server with parallel requests. Start at 10 and tune from there.
Summary
- Add retry logic with exponential backoff โ fixes most transient resets
- Disable keep-alive or set socket timeout shorter than the server's idle timeout
- Always set a request timeout so resets don't stall your process
- Always attach
.on('error', ...)on raw HTTP/HTTPS requests - Behind a proxy? Align timeouts between Node and the proxy layer

