This error occurs when a network request does not complete within the specified time limit and the socket connection times out. It commonly happens with HTTP clients when the server takes too long to respond or network connectivity issues prevent timely communication.
The ETIMEDOUT error (Error Timeout) is a system-level error code that Node.js raises when a socket operation exceeds its configured timeout period. This typically occurs during outgoing HTTP requests when the remote server fails to respond within the expected timeframe. When you make a network request in Node.js using libraries like axios, node-fetch, or the native http/https modules, a socket connection is established between your application and the remote server. If the server doesn't send data back before the timeout threshold is reached, Node.js terminates the connection and throws an ETIMEDOUT error. This error is distinct from server errors (like 500 Internal Server Error) because the timeout happens at the network/transport layer before any HTTP response is received. It indicates that the TCP connection was established but no data was transmitted within the allowed time window.
Set appropriate timeout values for your HTTP client. Most libraries use different defaults or no timeout at all.
For axios:
const axios = require('axios');
const response = await axios.get('https://api.example.com/data', {
timeout: 10000, // 10 seconds
});For native fetch (Node.js 18+):
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch('https://api.example.com/data', {
signal: controller.signal
});
clearTimeout(timeoutId);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request timed out');
}
}For native http/https modules:
const https = require('https');
const options = {
hostname: 'api.example.com',
path: '/data',
timeout: 10000 // 10 seconds
};
const req = https.request(options, (res) => {
// Handle response
});
req.on('timeout', () => {
req.destroy();
console.error('Request timed out');
});
req.end();Use persistent connections to reduce connection overhead and prevent socket exhaustion.
For axios:
const axios = require('axios');
const http = require('http');
const https = require('https');
const httpAgent = new http.Agent({ keepAlive: true });
const httpsAgent = new https.Agent({ keepAlive: true });
const client = axios.create({
httpAgent,
httpsAgent,
timeout: 10000
});
const response = await client.get('https://api.example.com/data');For native http/https:
const https = require('https');
const agent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 10000
});
const options = {
hostname: 'api.example.com',
path: '/data',
agent: agent
};This reuses existing connections instead of creating new ones for each request.
Add automatic retries for transient timeout errors to improve reliability.
Using axios-retry:
const axios = require('axios');
const axiosRetry = require('axios-retry');
axiosRetry(axios, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
return axiosRetry.isNetworkOrIdempotentRequestError(error) ||
error.code === 'ETIMEDOUT';
}
});
const response = await axios.get('https://api.example.com/data', {
timeout: 10000
});Custom implementation:
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetch(url, options);
} catch (error) {
if (error.code === 'ETIMEDOUT' && i < maxRetries - 1) {
const delay = Math.min(1000 * Math.pow(2, i), 10000);
console.log(`Retry ${i + 1} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}DNS resolution delays can contribute to timeouts. Verify DNS is working properly.
Test DNS resolution:
# Check DNS lookup time
time nslookup api.example.com
# Use dig for more details
dig api.example.comConfigure custom DNS servers in Node.js:
const dns = require('dns');
// Use Google DNS
dns.setServers(['8.8.8.8', '8.8.4.4']);
// Or Cloudflare DNS
dns.setServers(['1.1.1.1', '1.0.0.1']);For containerized environments, check /etc/resolv.conf:
cat /etc/resolv.confTrack active connections to identify socket exhaustion issues.
Check open sockets:
# View all established connections
netstat -an | grep ESTABLISHED
# Count connections by state
netstat -an | awk '/tcp/ {print $6}' | sort | uniq -c
# Check sockets for specific port
lsof -i :443Add logging in your application:
const https = require('https');
const agent = new https.Agent({
keepAlive: true,
maxSockets: 50
});
// Log socket statistics
setInterval(() => {
console.log('Socket stats:', {
requests: agent.requests,
sockets: agent.sockets,
freeSockets: agent.freeSockets
});
}, 10000);Server-side timeout configuration: If you control the server, ensure the server's keep-alive timeout is greater than your client timeout. In Express.js: server.keepAliveTimeout = 65000; server.headersTimeout = 66000;
AWS Lambda considerations: Lambda functions have a maximum execution time (15 minutes default). Enable connection reuse by setting AWS_NODEJS_CONNECTION_REUSE_ENABLED=1 environment variable. Use VPC endpoints when calling AWS services to avoid NAT gateway latency.
Timeout hierarchy: Be aware of multiple timeout layers: socket timeout (connection-level), request timeout (per-request), and global timeout (entire operation). Configure each appropriately.
Network monitoring: Use tools like tcpdump or Wireshark to capture network traffic and identify where delays occur. In production, consider APM tools like New Relic or Datadog to track request latency patterns.
Circuit breaker pattern: For critical services, implement circuit breakers to fail fast when a service is consistently timing out, preventing cascade failures and resource exhaustion.
IPv4 vs IPv6: Some networks have IPv6 connectivity issues that cause fallback delays. You can force IPv4: const agent = new https.Agent({ family: 4 });
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams