error nodejs
Node.js ETIMEDOUT
Understanding Node.js ETIMEDOUT error - the connection attempt timed out before a response was received from the server.
What It Means
ETIMEDOUT occurs when a connection or request attempt times out. The server did not respond within the allotted time. Unlike ECONNREFUSED (where the server actively rejects the connection), ETIMEDOUT means the server simply didn’t respond — it may be down, unreachable, or overloaded.
Common Causes
- Remote server is down or unreachable
- Network connectivity issues (DNS resolution, routing)
- Firewall silently dropping packets (no rejection)
- Server is overloaded and not responding in time
- Incorrect hostname or IP address
- Timeout configured too short for the operation
- VPN or proxy misconfiguration
- Database query taking too long
How to Fix
Set appropriate timeouts
// HTTP requests with axios
const axios = require('axios');
const response = await axios.get('https://api.example.com/data', {
timeout: 30000, // 30 seconds
});
// HTTP requests with fetch (Node.js 18+)
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000);
const response = await fetch('https://api.example.com/data', {
signal: controller.signal,
});
clearTimeout(timeoutId);
// Native http module
const http = require('http');
const req = http.get('http://api.example.com/data', { timeout: 30000 }, (res) => {
// handle response
});
req.on('timeout', () => {
req.destroy();
console.error('Request timed out');
});
Retry with exponential backoff
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, {
...options,
signal: AbortSignal.timeout(options.timeout || 10000),
});
return response;
} catch (error) {
const isTimeout = error.code === 'ETIMEDOUT' || error.name === 'TimeoutError';
if (isTimeout && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Timeout. Retrying in ${delay}ms...`);
await new Promise(r => setTimeout(r, delay));
} else {
throw error;
}
}
}
}
Fix database timeout
// PostgreSQL with pg
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
connectionTimeoutMillis: 10000, // 10s to establish connection
query_timeout: 30000, // 30s for queries
idle_timeout: 10000,
});
// MySQL with mysql2
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
connectTimeout: 10000,
// For individual queries:
});
const [rows] = await pool.query({
sql: 'SELECT * FROM large_table',
timeout: 30000,
});
Fix DNS resolution timeout
# Test DNS resolution
nslookup api.example.com
dig api.example.com
# Test connectivity
ping api.example.com
curl -v --connect-timeout 10 https://api.example.com/health
# Check if the server is reachable
nc -zv api.example.com 443 -w 5
Handle timeout gracefully
app.get('/api/external-data', async (req, res) => {
try {
const data = await fetchExternalAPI();
res.json(data);
} catch (error) {
if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
res.status(504).json({
error: 'Gateway Timeout',
message: 'External service is not responding',
});
} else {
throw error;
}
}
});
Configure keepalive for persistent connections
const http = require('http');
const https = require('https');
// Reuse connections to avoid repeated TCP handshakes
const agent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 1000,
timeout: 30000,
});
const response = await fetch('https://api.example.com/data', { agent });
Related Errors
- Node.js ECONNREFUSED - Connection actively refused (server is up but rejecting).
- Node.js ERR_HTTP_HEADERS_SENT - Headers already sent (can occur after timeout handling errors).