The FORMERR error occurs when a DNS server rejects a Node.js DNS query as malformed. This typically happens due to incompatible DNS extensions, invalid hostnames, or DNS server configuration issues.
The FORMERR (Format Error) error in Node.js indicates that a DNS server has rejected your application's DNS query because it considers the query to be malformed or improperly formatted. FORMERR is DNS response code 1, defined in RFC 1035. This error originates from the DNS server itself, not from Node.js. When you use methods like dns.lookup(), dns.resolve(), or dns.promises.resolve(), Node.js sends a DNS query to the configured DNS server. If that server cannot parse the query or finds it violates DNS protocol specifications, it responds with FORMERR. The error can occur with both the system-level dns.lookup() (which uses the OS DNS resolver) and the direct DNS protocol methods like dns.resolve() (which use Node.js's DNS implementation). Understanding which method you're using helps narrow down the cause, as they interact with DNS infrastructure differently.
First, verify that the hostname you're trying to resolve is valid:
const dns = require('dns');
// Check your hostname
const hostname = 'example.com'; // Replace with your actual hostname
// Validate basic format
if (!/^[a-zA-Z0-9.-]+$/.test(hostname)) {
console.log('Invalid hostname format:', hostname);
}
dns.lookup(hostname, (err, address) => {
if (err) {
console.error('DNS error:', err.code, err.message);
} else {
console.log('Resolved to:', address);
}
});Common invalid formats:
- Hostnames with spaces: "my server.com"
- URLs instead of hostnames: "https://example.com"
- Trailing dots in unexpected contexts
- Invalid characters like underscores in the wrong positions
Switch to Google's public DNS (8.8.8.8) or Cloudflare's DNS (1.1.1.1) to check if the issue is specific to your current DNS server:
const dns = require('dns');
// Set custom DNS servers
dns.setServers(['8.8.8.8', '1.1.1.1']);
dns.resolve4('example.com', (err, addresses) => {
if (err) {
console.error('Still failing with public DNS:', err.code);
} else {
console.log('Success with public DNS:', addresses);
}
});If this works, your system's default DNS server has compatibility issues. Update your network settings or /etc/resolv.conf to use these DNS servers permanently.
If you're using a custom DNS library or making raw DNS queries, try disabling EDNS options:
// If using a library like 'dns-packet' or similar
const packet = require('dns-packet');
const query = packet.encode({
type: 'query',
id: 1,
flags: packet.RECURSION_DESIRED,
questions: [{
type: 'A',
name: 'example.com'
}]
// Do NOT include edns_options or additional sections that might trigger FORMERR
});For native Node.js dns module, this is handled automatically, but third-party DNS libraries may need explicit configuration.
Switch to the promise-based DNS API with proper error handling and retry logic:
const dns = require('dns').promises;
async function resolveWithRetry(hostname, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const addresses = await dns.resolve4(hostname);
return addresses;
} catch (err) {
console.log(`Attempt ${attempt} failed:`, err.code);
if (err.code === 'FORMERR') {
// Try alternate resolution method
try {
const result = await dns.lookup(hostname);
return [result.address];
} catch (lookupErr) {
if (attempt === maxAttempts) throw lookupErr;
}
}
if (attempt === maxAttempts) throw err;
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
resolveWithRetry('example.com')
.then(addresses => console.log('Resolved:', addresses))
.catch(err => console.error('All attempts failed:', err));On Linux/macOS, verify your /etc/resolv.conf is properly configured:
# View current DNS servers
cat /etc/resolv.conf
# Should see entries like:
# nameserver 8.8.8.8
# nameserver 8.8.4.4If you see unusual or local DNS servers (like 127.0.0.53), you may be using systemd-resolved. Check its configuration:
# Check systemd-resolved status
systemctl status systemd-resolved
# View resolved DNS servers
resolvectl statusOn Docker containers, ensure the container's DNS configuration is correct:
# Run container with custom DNS
docker run --dns 8.8.8.8 --dns 8.8.4.4 your-image
# Or in docker-compose.yml:
# dns:
# - 8.8.8.8
# - 8.8.4.4Protocol-level considerations: FORMERR is specifically DNS response code 1 as defined in RFC 1035. Modern DNS servers support EDNS0 (RFC 6891), which allows larger UDP packets and additional options. However, some older DNS servers, corporate DNS proxies, or misconfigured servers may reject queries containing EDNS options they don't recognize.
UDP vs TCP fallback: By default, Node.js uses UDP for DNS queries. If a UDP query results in FORMERR, the underlying c-ares library (used by dns.resolve* methods) does not automatically fall back to TCP. However, dns.lookup() uses the operating system's resolver, which may handle this fallback differently depending on your OS.
Container and cloud environments: In Kubernetes, Docker, or cloud environments, DNS queries often go through intermediate DNS proxies or service discovery systems (like CoreDNS, kube-dns, or Docker's embedded DNS server). These systems may have specific limitations on query formats. For example, CoreDNS has a default configuration that may need adjustment for certain EDNS options.
Debugging with tcpdump: To see the exact DNS query being sent, capture DNS traffic:
sudo tcpdump -i any -n port 53 -vvRun your Node.js application and examine the DNS query packets. Look for EDNS options, query flags, or malformed question sections that might trigger FORMERR.
Alternative: Use DoH (DNS over HTTPS): If your DNS server has FORMERR issues with traditional DNS, consider using DNS over HTTPS with a library like 'dohdec':
const doh = require('dohdec');
doh.lookup('example.com', { method: 'POST' })
.then(response => console.log(response.answers))
.catch(err => console.error(err));This bypasses traditional DNS infrastructure entirely and may avoid FORMERR issues caused by intermediate DNS servers.
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