This error occurs when a DNS server fails to complete a hostname lookup in Node.js. It typically indicates DNS server configuration issues, DNSSEC validation failures, or network connectivity problems between your application and the DNS resolver.
The SERVFAIL error (Server Failure) is a DNS response code that indicates the DNS server encountered a general failure while attempting to resolve a hostname. In Node.js, this error surfaces when using DNS methods like `dns.lookup()`, `dns.resolve()`, or when making HTTP requests that require hostname resolution. When Node.js performs a DNS lookup, it queries configured DNS servers to translate domain names into IP addresses. A SERVFAIL response means the DNS server received the query but couldn't provide a valid answer due to internal errors, misconfigurations, or upstream issues. Unlike ENOTFOUND (hostname doesn't exist), SERVFAIL indicates the DNS infrastructure itself has a problem. This error is particularly common in containerized environments, corporate networks with strict DNS policies, or when dealing with DNSSEC-enabled domains where signature validation fails. The error code is standardized across DNS implementations, so Node.js simply surfaces what the underlying DNS resolver reports.
Check if your configured DNS servers are accessible and responding:
# Check DNS server connectivity (Linux/macOS)
nslookup google.com
dig google.com
# Test specific DNS server
nslookup google.com 8.8.8.8
dig @8.8.8.8 google.com
# Windows
nslookup google.comIf queries to public DNS servers (like 8.8.8.8 or 1.1.1.1) work but your default DNS fails, the issue is with your configured DNS server.
Configure Node.js to use reliable public DNS servers using the dns.setServers() method:
const dns = require('dns');
// Use Google Public DNS
dns.setServers(['8.8.8.8', '8.8.4.4']);
// Or Cloudflare DNS
// dns.setServers(['1.1.1.1', '1.0.0.1']);
// Test the resolution
dns.resolve('example.com', (err, addresses) => {
if (err) {
console.error('DNS resolution failed:', err);
} else {
console.log('Resolved addresses:', addresses);
}
});Important: dns.setServers() only affects dns.resolve() and related methods, not dns.lookup() which uses the OS resolver. For dns.lookup(), you must change system DNS settings.
If using dns.lookup() or making HTTP requests, modify your system's DNS settings:
Linux (/etc/resolv.conf):
sudo nano /etc/resolv.confAdd or modify nameserver entries:
nameserver 8.8.8.8
nameserver 8.8.4.4macOS:
# Temporary change
sudo networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4
# Revert to DHCP
sudo networksetup -setdnsservers Wi-Fi emptyWindows (PowerShell as Administrator):
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 8.8.8.8,8.8.4.4Docker containers:
Add DNS servers to docker-compose.yml:
services:
app:
dns:
- 8.8.8.8
- 8.8.4.4Add resilience to your application with caching and retries:
const dns = require('dns').promises;
async function resolveWithRetry(hostname, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const addresses = await dns.resolve4(hostname);
return addresses;
} catch (error) {
if (error.code === 'SERVFAIL' && i < retries - 1) {
console.log(`DNS SERVFAIL for ${hostname}, retry ${i + 1}/${retries}`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
// Usage
resolveWithRetry('example.com')
.then(addresses => console.log('Resolved:', addresses))
.catch(err => console.error('Failed after retries:', err));For HTTP requests, use a library with built-in DNS caching like cacheable-lookup:
npm install cacheable-lookupconst http = require('http');
const CacheableLookup = require('cacheable-lookup');
const cacheable = new CacheableLookup();
cacheable.install(http.globalAgent);
// Now all http requests use cached DNS lookupsDNSSEC failures often cause SERVFAIL errors. Test DNSSEC validation:
# Check DNSSEC status
dig +dnssec example.com
# Test with DNSSEC validation disabled
dig +cd example.comIf +cd (checking disabled) succeeds but regular queries fail, DNSSEC is the issue.
Disable DNSSEC validation in Node.js (not recommended for production):
// Use dns.resolve() with custom resolver that doesn't validate DNSSEC
const { Resolver } = require('dns');
const resolver = new Resolver();
resolver.setServers(['8.8.8.8']); // Use a resolver without strict DNSSEC
resolver.resolve4('example.com', (err, addresses) => {
console.log(addresses);
});Better solution: Contact the domain administrator to fix DNSSEC signatures.
Ensure DNS traffic (UDP/TCP port 53) is allowed:
# Test UDP DNS (most common)
nc -vuz 8.8.8.8 53
# Test TCP DNS (used for large responses)
nc -vz 8.8.8.8 53
# Check if DNS queries are being blocked
sudo tcpdump -i any port 53AWS environments: Check security groups and NACLs allow outbound UDP/TCP port 53.
Corporate networks: Some organizations block external DNS. Contact IT to whitelist your application or use internal DNS servers.
Docker: Verify DNS settings in /etc/docker/daemon.json:
{
"dns": ["8.8.8.8", "8.8.4.4"]
}DNS Resolver Differences in Node.js:
Node.js provides two DNS resolution mechanisms:
- dns.lookup(): Uses the OS's getaddrinfo() function, respects /etc/hosts, and cannot be configured via dns.setServers()
- dns.resolve(), dns.resolve4(), dns.resolve6(): Performs actual DNS queries, can be configured with dns.setServers(), bypasses /etc/hosts
HTTP modules like http and https use dns.lookup() by default, which is why dns.setServers() doesn't affect them.
AWS Route 53 SERVFAIL Issues:
In AWS environments, SERVFAIL responses often occur when:
- Route 53 Resolver outbound endpoints cannot reach on-premises DNS servers
- VPC DNS resolver IPs are blocked by third-party DNS providers
- Name server configurations in parent/child hosted zones don't match
Solution: Ensure security group egress rules allow UDP/TCP 53 to target IPs, and verify network ACLs.
DNSSEC and SERVFAIL:
DNSSEC adds cryptographic signatures to DNS records. Common DNSSEC-related SERVFAIL causes:
- Expired DNSSEC signatures (RRSIG records)
- Missing DS records in the parent zone
- Clock skew causing signature validation failures
- Key rollover errors
Use tools like dnsviz.net to visualize DNSSEC validation chains and identify signature issues.
Debugging in Production:
For production debugging without changing system DNS:
const { Resolver } = require('dns').promises;
async function debugDNS(hostname) {
const resolvers = [
{ name: 'Google', servers: ['8.8.8.8', '8.8.4.4'] },
{ name: 'Cloudflare', servers: ['1.1.1.1', '1.0.0.1'] },
{ name: 'System Default', servers: null }
];
for (const { name, servers } of resolvers) {
const resolver = servers ? new Resolver() : new Resolver();
if (servers) resolver.setServers(servers);
try {
const result = await resolver.resolve4(hostname);
console.log(`${name}: SUCCESS -`, result);
} catch (error) {
console.log(`${name}: FAILED -`, error.code);
}
}
}
debugDNS('example.com');Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process