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 });