HTTP requests fail when they exceed the configured timeout threshold, typically defaulting to 30 seconds. This occurs when the remote server is slow to respond, network connections are unstable, or response payloads are too large to process within the timeout window.
This error occurs when an HTTP client request (using axios, fetch, or native http/https modules) exceeds its configured timeout threshold before receiving a complete response from the remote server. The default timeout of 30000ms (30 seconds) is a common configuration across many Node.js HTTP libraries. The timeout mechanism protects your application from hanging indefinitely when remote services are unresponsive. When triggered, it immediately aborts the request and throws this error, allowing your application to handle the failure gracefully rather than waiting forever for a response that may never arrive. This is distinct from connection errors (ECONNREFUSED) or network errors (ECONNRESET) - the connection was established successfully, but the server failed to send a complete response within the allowed time.
If the operation genuinely requires more time, configure a higher timeout value. For axios:
const axios = require('axios');
// Set timeout for specific request
const response = await axios.get('https://api.example.com/data', {
timeout: 60000 // 60 seconds
});
// Or configure globally
const client = axios.create({
timeout: 60000,
baseURL: 'https://api.example.com'
});For native fetch API (Node.js 18+):
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 60000);
try {
const response = await fetch('https://api.example.com/data', {
signal: controller.signal
});
clearTimeout(timeoutId);
} catch (error) {
if (error.name === 'AbortError') {
console.error('Request timed out');
}
}For native http/https modules:
const https = require('https');
const options = {
hostname: 'api.example.com',
path: '/data',
timeout: 60000
};
const req = https.get(options, (res) => {
// Handle response
});
req.on('timeout', () => {
req.destroy();
console.error('Request timed out');
});For transient timeout issues, add automatic retry mechanisms:
const axios = require('axios');
async function fetchWithRetry(url, maxRetries = 3, baseDelay = 1000) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await axios.get(url, { timeout: 30000 });
return response.data;
} catch (error) {
if (error.code === 'ECONNABORTED' && i < maxRetries - 1) {
const delay = baseDelay * Math.pow(2, i);
console.log(`Request timeout, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
// Usage
try {
const data = await fetchWithRetry('https://api.example.com/data');
console.log(data);
} catch (error) {
console.error('Request failed after retries:', error.message);
}Optimize connection management to reduce overhead:
const axios = require('axios');
const http = require('http');
const https = require('https');
// Create HTTP agents with connection pooling
const httpAgent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
// Use agents with axios
const client = axios.create({
httpAgent,
httpsAgent,
timeout: 30000
});This reduces connection establishment overhead and prevents socket exhaustion.
Distinguish timeout errors from other failures and handle appropriately:
const axios = require('axios');
async function makeRequest(url) {
try {
const response = await axios.get(url, { timeout: 30000 });
return response.data;
} catch (error) {
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
console.error('Request timeout:', {
url: error.config?.url,
timeout: error.config?.timeout,
duration: Date.now() - error.config?.startTime
});
// Return cached data, default value, or rethrow
throw new Error('Service temporarily unavailable');
}
if (error.response) {
// Server responded with error status
console.error('Server error:', error.response.status);
} else if (error.request) {
// Request made but no response received
console.error('No response received');
}
throw error;
}
}
// Add request timing for debugging
axios.interceptors.request.use(config => {
config.startTime = Date.now();
return config;
});
axios.interceptors.response.use(
response => {
const duration = Date.now() - response.config.startTime;
console.log(`Request completed in ${duration}ms`);
return response;
},
error => {
if (error.config?.startTime) {
const duration = Date.now() - error.config.startTime;
console.error(`Request failed after ${duration}ms`);
}
return Promise.reject(error);
}
);Investigate the root cause of timeouts:
const axios = require('axios');
const { performance } = require('perf_hooks');
// Create detailed timing logger
function createTimingLogger() {
return {
dnsLookupStart: 0,
tcpConnectionStart: 0,
tlsHandshakeStart: 0,
requestStart: 0,
responseStart: 0,
responseEnd: 0
};
}
// Log request with detailed timing
async function debugRequest(url) {
const timing = createTimingLogger();
const startTime = performance.now();
try {
const response = await axios.get(url, {
timeout: 30000,
onDownloadProgress: (progressEvent) => {
if (!timing.responseStart) {
timing.responseStart = performance.now() - startTime;
}
}
});
timing.responseEnd = performance.now() - startTime;
console.log('Request timing breakdown:', {
total: `${timing.responseEnd.toFixed(2)}ms`,
url,
size: response.headers['content-length'],
status: response.status
});
return response;
} catch (error) {
const failTime = performance.now() - startTime;
console.error('Request failed:', {
url,
duration: `${failTime.toFixed(2)}ms`,
error: error.code || error.message,
timeout: error.config?.timeout
});
throw error;
}
}
// Usage
debugRequest('https://api.example.com/data');Check network latency:
# Test DNS resolution time
time nslookup api.example.com
# Test connection time
time curl -o /dev/null -s -w "Total time: %{time_total}s\n" https://api.example.com/data
# Trace route to identify network hops
traceroute api.example.comTimeout Hierarchy: Different timeout types exist in HTTP requests - DNS timeout, connection timeout, socket timeout, and response timeout. The "request timeout" typically encompasses all phases. Understanding which phase is slow helps target optimizations.
Server-Side Considerations: If you control the server, implement streaming responses for large payloads, optimize database queries, add response compression, and consider pagination for large datasets. Long-running operations should use webhooks or polling patterns rather than synchronous requests.
Environment-Specific Timeouts: Cloud functions (AWS Lambda, Google Cloud Functions) have hard execution limits (typically 30-900 seconds). Set your HTTP timeouts well below these limits to ensure graceful error handling. Container orchestrators like Kubernetes have their own timeout configurations that may override application settings.
Global vs Local Timeouts: Setting timeouts globally affects all requests. For APIs with mixed operation durations, configure timeouts per-endpoint:
const fastEndpoint = await axios.get('/quick', { timeout: 5000 });
const slowEndpoint = await axios.get('/report', { timeout: 120000 });Debugging Techniques: Use tools like tcpdump, wireshark, or Node.js built-in diagnostics to capture network traffic. Enable debug logging in HTTP libraries (axios has axios.defaults.debug = true in some configurations).
Related Error Codes: ECONNABORTED (connection aborted), ESOCKETTIMEDOUT (socket-level timeout), and ETIMEDOUT are often used interchangeably depending on the HTTP library. Always check both error.code and error.message for robust error handling.
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