How to fix Error: read ECONNRESET in Node.js
This error occurs when a TCP connection is forcibly closed by the remote server or peer before the operation completes. It typically happens during HTTP requests when the server closes the connection unexpectedly, often due to timeout mismatches, keep-alive issues, or network problems.
Quick fix
Fixes ECONNRESET
const http = require('http');
function makeRequest(url, retries = 3) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve(data));
}).on('error', (err) => {
if (err.code === 'ECONNRESET' && retries > 0) {
console.log(`ECONNRESET occurred, retrying... (${retries} attempts left)`);
setTimeout(() => {
makeRequest(url, retries - 1).then(resolve).catch(reject);
}, 1000); // Wait 1 second before retry
} else {
reject(err);
}
});
});
}- Implement proper error handling for ECONNRESET
- Configure client timeout shorter than server timeout
- Use a keep-alive agent with proper buffer settings
- Adjust server-side timeout settings if you control the server
const http = require('http');function makeRequest(url, retries = 3) {return new Promise((resolve, reject) => {http.get(url, (res) => {let data = '';res.on('data', (chunk) => data += chunk);res.on('end', () => resolve(data));}).on('error', (err) => {if (err.code === 'ECONNRESET' && retries > 0) {console.log(`ECONNRESET occurred, retrying... (${retries} attempts left)`);setTimeout(() => {makeRequest(url, retries - 1).then(resolve).catch(reject);}, 1000); // Wait 1 second before retry} else {reject(err);}});});}Error: read ECONNRESET
What this error means
The ECONNRESET error is a network-level error that occurs at the TCP layer when one side of a connection sends a TCP RST (reset) packet to the other side, immediately terminating the connection. In Node.js, this manifests as "Error: read ECONNRESET" or "Error: write ECONNRESET" depending on whether you were reading from or writing to the socket when it was reset. This error is particularly common when using HTTP keep-alive connections. When a server closes an idle connection that a client is trying to reuse from its connection pool, the client receives an ECONNRESET error. The timing window between when the server decides to close the connection and when the client attempts to use it creates a race condition that's difficult to avoid entirely. The error indicates that the remote peer (server) has abruptly closed the connection without following the normal TCP connection termination handshake. This is different from a graceful close (FIN packet) and suggests either an error condition on the remote side or a timeout/resource constraint that forced the connection to be terminated immediately.
Typical symptoms
- HTTP requests fail intermittently with "Error: read ECONNRESET"
- Errors occur more frequently under high load or with concurrent requests
- Database connection errors showing ECONNRESET after idle periods
- External API calls fail randomly, especially with keep-alive enabled
- The error happens more often after the first 100+ consecutive requests
- Connection pool exhaustion or socket reuse failures
- Errors correlate with specific timeout thresholds (commonly 5-15 seconds)
Common causes
- Server closed an idle keep-alive connection that the client tried to reuse
- Client timeout setting is longer than server timeout, creating a timing mismatch
- Server is overwhelmed and forcibly closing connections to free resources
- Firewall or load balancer terminating idle connections
- Network instability or intermittent connectivity issues
- VPN interference disrupting TCP connections
- Server crashed or restarted during the connection
- Proxy or CDN between client and server resetting connections
- Server-side request timeout enforced by reverse proxy or application server
- SSL/TLS handshake failures or certificate issues
How to fix "Error: read ECONNRESET"
Add error handling to catch and retry ECONNRESET errors gracefully:
const http = require('http');
function makeRequest(url, retries = 3) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve(data));
}).on('error', (err) => {
if (err.code === 'ECONNRESET' && retries > 0) {
console.log(`ECONNRESET occurred, retrying... (${retries} attempts left)`);
setTimeout(() => {
makeRequest(url, retries - 1).then(resolve).catch(reject);
}, 1000); // Wait 1 second before retry
} else {
reject(err);
}
});
});
}This ensures temporary connection resets don't crash your application.
The most important fix: ensure your client timeout is shorter than the server's keep-alive timeout. If the server closes idle connections after 5 seconds, set your client timeout to 4 seconds:
const http = require('http');
const https = require('https');
// For http module
const agent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 3000, // 3 seconds
timeout: 4000, // 4 seconds (shorter than server's 5s)
maxSockets: 50,
});
// For https module
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 3000,
timeout: 4000,
maxSockets: 50,
});
// Use the agent in requests
http.get('http://example.com', { agent }, (res) => {
// handle response
});For libraries like axios:
const axios = require('axios');
const http = require('http');
const https = require('https');
const httpAgent = new http.Agent({
keepAlive: true,
timeout: 4000,
});
const httpsAgent = new https.Agent({
keepAlive: true,
timeout: 4000,
});
const client = axios.create({
httpAgent,
httpsAgent,
timeout: 5000, // Request timeout
});Install and configure agentkeepalive with a safety buffer to close sockets before the server does:
npm install agentkeepaliveconst Agent = require('agentkeepalive');
const keepaliveAgent = new Agent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000, // Active socket timeout
freeSocketTimeout: 30000, // Free socket timeout (30s)
keepAliveTimeout: 60000, // Keep-alive timeout
socketActiveTTL: 110000, // Max time socket can be alive
});
const http = require('http');
http.get({
host: 'example.com',
port: 80,
path: '/',
agent: keepaliveAgent,
}, (res) => {
// handle response
});The key is setting freeSocketTimeout shorter than the server's timeout to prevent reusing dead sockets.
If you're running the Node.js server that's causing ECONNRESET errors for clients, increase the timeouts:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
// Set keep-alive timeout to 65 seconds (longer than most client defaults)
server.keepAliveTimeout = 65000;
// Set headers timeout slightly higher than keepAliveTimeout
server.headersTimeout = 66000;
// Set overall request timeout
server.timeout = 120000;
server.listen(3000, () => {
console.log('Server running on port 3000');
});For Express.js:
const express = require('express');
const app = express();
const server = app.listen(3000, () => {
console.log('Server running on port 3000');
});
server.keepAliveTimeout = 65000;
server.headersTimeout = 66000;For production environments, use a sophisticated retry mechanism with exponential backoff:
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
return response;
} catch (error) {
const isLastAttempt = attempt === maxRetries;
const isRetriableError =
error.code === 'ECONNRESET' ||
error.code === 'ETIMEDOUT' ||
error.code === 'ECONNREFUSED';
if (isLastAttempt || !isRetriableError) {
throw error;
}
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
fetchWithRetry('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.error('All retries failed:', err));Add detailed logging to understand when and why connections are being reset:
const http = require('http');
const agent = new http.Agent({
keepAlive: true,
});
// Monitor socket lifecycle
agent.on('free', (socket, host, port) => {
console.log(`Socket freed: ${host}:${port}`);
});
const req = http.get('http://example.com', { agent }, (res) => {
console.log(`Response status: ${res.statusCode}`);
res.on('data', () => {});
res.on('end', () => console.log('Response complete'));
});
req.on('socket', (socket) => {
console.log('Socket assigned to request');
socket.on('connect', () => console.log('Socket connected'));
socket.on('timeout', () => console.log('Socket timeout'));
socket.on('end', () => console.log('Socket ended'));
socket.on('close', (hadError) => console.log(`Socket closed (error: ${hadError})`));
});
req.on('error', (err) => {
console.error('Request error:', {
code: err.code,
message: err.message,
syscall: err.syscall,
});
});Advanced notes
Keep-Alive Timeout Race Condition:
The ECONNRESET error is often unavoidable due to a fundamental race condition in HTTP keep-alive. When a server decides to close an idle connection, it sends a FIN packet. If a client sends a request on that socket in the brief moment after the server has decided to close but before the client receives the FIN, the server responds with a RST (reset), causing ECONNRESET. The solution is not to eliminate the error entirely but to handle it gracefully with retries.
Node.js Default Behavior:
Node.js HTTP server defaults changed in version 8.0.0. The default server.keepAliveTimeout is 5 seconds, while many client libraries use longer defaults (15+ seconds). This mismatch is the root cause of many ECONNRESET errors in production.
Connection Pool Considerations:
When using database drivers (PostgreSQL, MySQL, MongoDB) or HTTP client libraries with connection pooling, configure pool-specific timeout settings. Most pools have idle timeout settings that should be shorter than the server's connection timeout.
Load Balancer and Reverse Proxy Impact:
Services like AWS ALB, NGINX, and CloudFront have their own timeout settings that can cause ECONNRESET. For example, AWS ALB has a 60-second idle timeout by default. Ensure your client timeouts align with all intermediary infrastructure.
Debugging Production Issues:
Use tools like tcpdump or Wireshark to capture TCP RST packets and determine which side is initiating the reset. The NODE_DEBUG=http environment variable enables verbose HTTP module debugging in Node.js.
VPN and Corporate Firewall Issues:
Corporate networks often have aggressive firewall rules that reset idle TCP connections after 30-60 seconds. If errors only occur in specific network environments, investigate firewall and NAT timeout settings.
Frequently asked questions
- What does "ECONNRESET" mean?
- The ECONNRESET error is a network-level error that occurs at the TCP layer when one side of a connection sends a TCP RST (reset) packet to the other side, immediately terminating the connection. js, this manifests as "Error: read ECONNRESET" or "Error: write ECONNRESET" depending on whether you were reading from or writing to the socket when it was reset. This error is particularly common when using HTTP keep-alive connections.
- How do I fix "ECONNRESET"?
- This error occurs when a TCP connection is forcibly closed by the remote server or peer before the operation completes. It typically happens during HTTP requests when the server closes the connection unexpectedly, often due to timeout mismatches, keep-alive issues, or network problems.
- What causes "ECONNRESET"?
- Server closed an idle keep-alive connection that the client tried to reuse Client timeout setting is longer than server timeout, creating a timing mismatch Server is overwhelmed and forcibly closing connections to free resources
- Is the "ECONNRESET" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐Node.js Official Documentation
- ๐Node.js Error Documentation - System Errors(Official Docs)
- ๐Node.js Net Module - Socket Error Handling(Official Docs)
- ๐
- ๐