The ENOTFOUND error occurs when Node.js cannot resolve a hostname to an IP address through DNS lookup. This typically happens with invalid hostnames, typos in URLs, network connectivity issues, or DNS configuration problems.
The "getaddrinfo ENOTFOUND" error in Node.js indicates that DNS resolution failed for the specified hostname. When Node.js attempts to make an HTTP/HTTPS request or any network operation requiring hostname resolution, it uses the dns.lookup() function which ultimately calls getaddrinfo, a C standard library function for DNS resolution. This error is thrown when the DNS resolver cannot find an IP address associated with the provided hostname. According to the official Node.js documentation, the error code is set to 'ENOTFOUND' not only when the hostname does not exist, but also when the lookup fails in other ways such as no available file descriptors or other system-level issues. The error typically appears in operations involving the http, https, or dns modules, and can occur during any network request that requires hostname resolution. Under the hood, Node HTTP clients use dns.lookup() by default, which makes them susceptible to DNS-related failures. The error occurs at the DNS resolution stage, before any actual network connection is attempted.
Check your code for typos in the hostname. Make sure you're using only the domain name, without protocol or port:
// ❌ Wrong - includes protocol and port in hostname
const options = {
hostname: 'https://api.example.com:443',
path: '/data'
};
// ✅ Correct - only the domain name
const options = {
hostname: 'api.example.com',
port: 443,
path: '/data'
};
// With fetch - use full URL
const response = await fetch('https://api.example.com/data');If using environment variables, log the value to verify it's correct:
const hostname = process.env.API_HOSTNAME;
console.log('Using hostname:', hostname);
console.log('Hostname type:', typeof hostname);
console.log('Hostname length:', hostname?.length);Check for common mistakes like extra whitespace, trailing slashes, or mixed http/https.
Use Node.js's dns module to test if the hostname can be resolved:
const dns = require('dns');
const { promisify } = require('util');
const lookup = promisify(dns.lookup);
async function testHostname(hostname) {
try {
const result = await lookup(hostname);
console.log('✓ DNS resolved successfully:');
console.log(' Hostname:', hostname);
console.log(' Address:', result.address);
console.log(' Family:', result.family === 4 ? 'IPv4' : 'IPv6');
} catch (err) {
console.error('✗ DNS lookup failed:');
console.error(' Error code:', err.code);
console.error(' Hostname:', err.hostname);
console.error(' Message:', err.message);
}
}
testHostname('api.example.com');If DNS lookup fails in Node.js but works in your terminal, it may indicate a Node.js-specific DNS configuration issue.
Verify the hostname can be resolved using system DNS tools:
# Using nslookup
nslookup api.example.com
# Using dig for detailed information
dig api.example.com
# Using host command
host api.example.com
# Test connectivity to the domain
ping api.example.com
# On Windows, use nslookup
nslookup api.example.comIf the hostname resolves in your terminal but fails in Node.js, this points to a Node.js configuration or DNS caching issue rather than a network problem.
If the hostname doesn't resolve in your terminal either, the issue is with your network or DNS configuration, not your code.
Check that your system has internet access and can reach DNS servers:
# Test connection to Google DNS
ping 8.8.8.8
# Check your system's configured DNS servers
cat /etc/resolv.conf # Linux/macOS
ipconfig /all # Windows (look for DNS Servers)
# Try to resolve a known working domain
nslookup google.comIf you can't reach external DNS servers or public domains:
- Check your network connection
- Verify firewall isn't blocking port 53 (DNS)
- Check if you're behind a corporate proxy that requires configuration
- Try switching to a public DNS server (8.8.8.8 or 1.1.1.1)
If you're getting ENOTFOUND for localhost or custom domains, verify your hosts file:
Linux and macOS:
# View current hosts file
cat /etc/hosts
# Edit hosts file (requires sudo)
sudo nano /etc/hosts
# Ensure these entries exist:
127.0.0.1 localhost
::1 localhost
# For custom domains, add entries like:
127.0.0.1 api.local
127.0.0.1 db.localWindows:
# File location: C:\Windows\System32\drivers\etc\hosts
# Open as Administrator:
127.0.0.1 localhost
::1 localhostAfter editing the hosts file, flush your DNS cache:
# macOS
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
# Linux (systemd)
sudo systemd-resolve --flush-caches
# Windows (run as Administrator)
ipconfig /flushdnsIf your default DNS servers are unreliable, configure Node.js to use different DNS servers:
const dns = require('dns');
const { Resolver } = dns;
// Create a custom resolver with public DNS servers
const resolver = new Resolver();
resolver.setServers([
'8.8.8.8', // Google DNS
'8.8.4.4', // Google DNS (backup)
'1.1.1.1', // Cloudflare DNS
'1.0.0.1' // Cloudflare DNS (backup)
]);
// Now use this resolver for DNS lookups
const { promisify } = require('util');
const resolve4 = promisify(resolver.resolve4.bind(resolver));
async function lookupWithCustomDNS(hostname) {
try {
const addresses = await resolve4(hostname);
console.log('Resolved to:', addresses[0]);
} catch (err) {
console.error('Failed to resolve:', err.message);
}
}
lookupWithCustomDNS('api.example.com');Or configure your system to use public DNS:
macOS:
sudo networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4Linux (systemd):
sudo nano /etc/systemd/resolved.conf
# Add: DNS=8.8.8.8 1.1.1.1
sudo systemctl restart systemd-resolvedImplement error handling to gracefully manage DNS lookup failures:
const https = require('https');
const axios = require('axios');
// Example 1: Using native HTTP module
function makeRequest(hostname, path) {
const options = {
hostname: hostname,
port: 443,
path: path,
method: 'GET'
};
const req = https.request(options, (res) => {
console.log('Status:', res.statusCode);
});
req.on('error', (err) => {
if (err.code === 'ENOTFOUND') {
console.error('DNS lookup failed!');
console.error('Hostname:', err.hostname);
console.error('Check hostname spelling and DNS configuration');
// Implement retry logic or fallback
} else if (err.code === 'ECONNREFUSED') {
console.error('Connection refused - service may be down');
} else if (err.code === 'ETIMEDOUT') {
console.error('Request timed out');
} else {
console.error('Request error:', err.message);
}
});
req.end();
}
// Example 2: Using axios
async function makeRequestWithAxios(url) {
try {
const response = await axios.get(url);
console.log('Success:', response.status);
} catch (err) {
if (err.code === 'ENOTFOUND') {
console.error('DNS failed for:', err.hostname);
// Retry with different hostname or use fallback
} else {
console.error('Error:', err.message);
}
}
}
// Example 3: Using fetch (Node.js 18+)
async function makeRequestWithFetch(url) {
try {
const response = await fetch(url);
console.log('Success:', response.status);
} catch (err) {
if (err.code === 'ENOTFOUND') {
console.error('Hostname not found:', err.hostname);
} else {
console.error('Request failed:', err.message);
}
}
}For applications making frequent requests to the same hostnames, implement DNS caching to reduce lookup overhead and potential failures:
const dns = require('dns');
const { promisify } = require('util');
// Simple DNS cache implementation
class DNSCache {
constructor(ttl = 300000) { // 5 minutes default
this.cache = new Map();
this.ttl = ttl;
}
async lookup(hostname) {
// Check if cached and not expired
if (this.cache.has(hostname)) {
const entry = this.cache.get(hostname);
if (Date.now() < entry.expiry) {
console.log('DNS cache hit for:', hostname);
return entry.address;
}
this.cache.delete(hostname);
}
// Perform actual DNS lookup
const lookup = promisify(dns.lookup);
try {
const result = await lookup(hostname);
const address = result.address;
// Cache the result
this.cache.set(hostname, {
address,
expiry: Date.now() + this.ttl
});
console.log('DNS cache miss, resolved:', hostname, 'to', address);
return address;
} catch (err) {
console.error('DNS lookup failed for:', hostname);
throw err;
}
}
}
// Usage
const dnsCache = new DNSCache(300000); // 5 minute TTL
async function testCaching() {
try {
const ip1 = await dnsCache.lookup('api.example.com');
console.log('First lookup:', ip1);
const ip2 = await dnsCache.lookup('api.example.com');
console.log('Second lookup (cached):', ip2);
} catch (err) {
console.error('Error:', err.message);
}
}
testCaching();You can also use HTTP keep-alive to reduce DNS lookups:
const https = require('https');
const axios = require('axios');
// Create agent with keep-alive
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 10000,
maxSockets: 50
});
// Use with axios
const client = axios.create({
httpsAgent,
timeout: 5000
});
// Use with fetch (Node.js 18+)
const response = await fetch('https://api.example.com/data', {
agent: httpsAgent
});DNS Resolution Methods in Node.js
Node.js provides multiple DNS resolution methods with different characteristics:
- dns.lookup(): Uses the system's getaddrinfo() function, respects /etc/hosts and system DNS configuration, default timeout ~3500ms
- dns.resolve(): Directly queries DNS servers, bypasses /etc/hosts, doesn't respect system-level host overrides
- dns.resolve4(): Resolves to IPv4 addresses only
- dns.resolve6(): Resolves to IPv6 addresses only
Container and Cloud Environment Issues
In Docker containers, Kubernetes pods, or cloud VMs, DNS resolution can fail due to:
1. Docker container DNS: The container's /etc/resolv.conf may point to an unavailable nameserver. Fix with:
docker run --dns 8.8.8.8 my-app2. Kubernetes DNS: CoreDNS may not be running or properly configured. Check:
kubectl get pods -n kube-system | grep coredns3. Cloud environment network: Some cloud providers require specific DNS configuration. Check your cloud provider's documentation.
IPv6 vs IPv4 Issues
Some systems have IPv6 enabled but DNS resolution may fail. Force IPv4 resolution:
const dns = require('dns');
const { promisify } = require('util');
const lookup = promisify((hostname, callback) => {
dns.lookup(hostname, { family: 4 }, callback);
});
const ipv4Address = await lookup('api.example.com');DNS Timeout and Retry Logic
Implement exponential backoff for DNS failures:
async function lookupWithRetry(hostname, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const lookup = require('util').promisify(require('dns').lookup);
return await lookup(hostname);
} catch (err) {
if (i === maxRetries - 1) throw err;
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
console.log(`Retry ${i + 1} after ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
}
}
}Corporate Network and Proxy Issues
If behind a corporate firewall or proxy:
1. Check if your proxy requires authentication
2. Set environment variables:
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.13. Verify your internal DNS servers are configured
4. Check if external domains are blocked by policy
Debugging DNS Issues
Enable detailed logging:
const dns = require('dns');
// Enable debug logging
dns.setServers(['8.8.8.8']);
dns.lookup('api.example.com', { all: true }, (err, addresses) => {
if (err) {
console.error('Full error object:', {
code: err.code,
errno: err.errno,
syscall: err.syscall,
hostname: err.hostname,
message: err.message
});
} else {
console.log('All resolved addresses:', addresses);
}
});Health Checks and Monitoring
Implement DNS health checks in your application startup:
async function healthCheckDNS(hostname) {
const lookup = require('util').promisify(require('dns').lookup);
try {
await lookup(hostname);
console.log('✓ DNS health check passed for:', hostname);
} catch (err) {
console.error('✗ DNS health check failed for:', hostname);
process.exit(1);
}
}
// In your app startup
await healthCheckDNS('api.example.com');
await healthCheckDNS('db.example.com');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