ETIMEDOUT occurs when a network operation in Node.js does not complete within the specified or default time limit. This typically happens during HTTP requests, database connections, or socket operations when the remote server fails to respond in time.
ETIMEDOUT is a timeout error that signals a network operation failed because the connected party did not properly respond within the allocated time period. This error is emitted by Node.js when attempting to establish or maintain a connection that exceeds the timeout threshold. The error typically occurs in the network layer when Node.js is unable to complete a TCP connection, send data, or receive a response from a remote server. Unlike connection refused errors, ETIMEDOUT means the connection attempt was made but no response was received before the timeout expired. This is one of the most common networking errors in Node.js applications, especially those making HTTP requests to external APIs, connecting to databases, or performing other I/O operations over unreliable networks.
Set appropriate timeout values based on your expected response times. Different HTTP libraries handle timeouts differently:
Native http/https module:
const http = require('http');
const options = {
hostname: 'api.example.com',
port: 80,
path: '/data',
timeout: 10000 // 10 seconds
};
const req = http.get(options, (res) => {
// Handle response
});
req.on('timeout', () => {
req.destroy();
console.error('Request timed out');
});
req.on('error', (err) => {
if (err.code === 'ETIMEDOUT') {
console.error('Connection timed out');
}
});Axios:
const axios = require('axios');
const response = await axios.get('https://api.example.com/data', {
timeout: 10000 // 10 seconds
});Fetch API (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 (err) {
if (err.name === 'AbortError') {
console.error('Request timed out');
}
}Start with conservative timeouts (30-60 seconds) and adjust based on your monitoring data.
Keep-Alive allows Node.js to reuse TCP connections, reducing the overhead of establishing new connections and avoiding timeout issues:
const http = require('http');
const https = require('https');
// Create agents with Keep-Alive enabled
const httpAgent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30000, // Keep connection alive for 30 seconds
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
// Use with axios
const axios = require('axios');
axios.defaults.httpAgent = httpAgent;
axios.defaults.httpsAgent = httpsAgent;
// Or with fetch
const response = await fetch('https://api.example.com/data', {
agent: httpsAgent
});This is especially important in serverless environments like AWS Lambda where connection pooling significantly improves performance.
Handle transient network failures gracefully by retrying failed requests:
Using axios-retry:
const axios = require('axios');
const axiosRetry = require('axios-retry');
axiosRetry(axios, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
return error.code === 'ETIMEDOUT' ||
error.code === 'ECONNABORTED' ||
axiosRetry.isNetworkOrIdempotentRequestError(error);
}
});
const response = await axios.get('https://api.example.com/data', {
timeout: 10000
});Custom retry implementation:
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
return response;
} catch (err) {
const isLastAttempt = i === maxRetries - 1;
if (isLastAttempt || err.name !== 'AbortError') {
throw err;
}
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}Verify that outbound connections are not being blocked:
Test connectivity:
# Test if you can reach the target host
ping api.example.com
# Check if the port is accessible
telnet api.example.com 443
# Or use curl to test the endpoint
curl -v --max-time 10 https://api.example.com/data
# Check your DNS resolution
nslookup api.example.com
dig api.example.comCommon firewall/network fixes:
- Check cloud security groups (AWS, Azure, GCP) allow outbound HTTPS/HTTP
- Verify corporate proxy settings if behind a corporate network
- Review VPC routing tables and network ACLs
- Ensure no rate limiting at the network level
- Configure proxy in Node.js if required:
const axios = require('axios');
axios.get('https://api.example.com/data', {
proxy: {
protocol: 'http',
host: 'proxy.company.com',
port: 8080
},
timeout: 10000
});DNS resolution delays can cause timeouts. Switch to reliable DNS servers:
On Linux/macOS, edit /etc/resolv.conf:
# Add Google DNS
nameserver 8.8.8.8
nameserver 8.8.4.4
# Or Cloudflare DNS
nameserver 1.1.1.1
nameserver 1.0.0.1On Windows (PowerShell as Administrator):
# Set DNS to Google
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses ("8.8.8.8","8.8.4.4")
# Or Cloudflare
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses ("1.1.1.1","1.0.0.1")Configure DNS timeout in Node.js:
const dns = require('dns');
dns.setDefaultResultOrder('ipv4first');
// For custom DNS resolution
const resolver = new dns.Resolver();
resolver.setServers(['8.8.8.8', '8.8.4.4']);Excessive concurrent connections can exhaust available sockets and cause timeouts:
Check current socket usage:
# On Linux/macOS
lsof -i -P -n | grep node
# Count active connections
netstat -an | grep ESTABLISHED | wc -l
# Check system limits
ulimit -nIncrease system limits if needed:
# Temporary increase (Linux/macOS)
ulimit -n 65536
# Permanent increase - edit /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536Configure connection pooling in your application:
const http = require('http');
const agent = new http.Agent({
maxSockets: 50, // Max concurrent connections
maxFreeSockets: 10, // Keep some connections in pool
timeout: 60000,
keepAlive: true
});
// Monitor socket usage
setInterval(() => {
console.log('Sockets in use:', Object.keys(agent.sockets).length);
console.log('Free sockets:', Object.keys(agent.freeSockets).length);
}, 10000);Server Keep-Alive Configuration:
When using Node.js as both client and server, ensure the server's keepAliveTimeout is greater than the client's timeout. The default Node.js HTTP server timeout is 5 seconds, which can cause race conditions:
const server = http.createServer((req, res) => {
// Your handler
});
server.keepAliveTimeout = 65000; // 65 seconds
server.headersTimeout = 66000; // Slightly higher than keepAliveTimeoutIPv6 vs IPv4 Issues:
Some environments have broken IPv6 connectivity, causing Node.js to attempt IPv6 connections that timeout before falling back to IPv4. Force IPv4 resolution:
const dns = require('dns');
dns.setDefaultResultOrder('ipv4first');AWS Lambda Considerations:
Lambda functions experience frequent ETIMEDOUT errors due to cold starts and connection limits. Always use Keep-Alive agents and consider warming strategies:
// Reuse agents across invocations (outside handler)
const httpsAgent = new https.Agent({
keepAlive: true,
maxSockets: 50
});
exports.handler = async (event) => {
const response = await axios.get(url, { httpsAgent });
return response.data;
};Debugging Timeout Sources:
Use Node.js diagnostics to identify which operations are timing out:
const { performance } = require('perf_hooks');
async function timedFetch(url) {
const start = performance.now();
try {
const response = await fetch(url);
console.log(`Request took ${performance.now() - start}ms`);
return response;
} catch (err) {
console.log(`Failed after ${performance.now() - start}ms`, err.code);
throw err;
}
}Progressive Timeout Strategy:
For critical operations, implement progressive timeouts with fallback strategies:
async function fetchWithFallback(primaryUrl, fallbackUrl) {
try {
return await fetch(primaryUrl, { timeout: 5000 });
} catch (err) {
if (err.code === 'ETIMEDOUT') {
console.log('Primary timed out, trying fallback');
return await fetch(fallbackUrl, { timeout: 10000 });
}
throw err;
}
}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