denoland/deno · error · NodeError
ERR_DNS_SET_SERVERS_FAILED
ERR_DNS_SET_SERVERS_FAILED
Error message
c-ares failed to set servers: "${err}" [${servers}] What it means
After parsing, setServers() hands the tuple list to the native layer (_handle.setServers). If that returns nonzero, the polyfill first restores the previous server list (setServers rejoined from the originals), then throws ERR_DNS_SET_SERVERS_FAILED with the native error string and the servers value. It means entries survived JS parsing but the native resolver rejected them (bad ports, unsupported tuples) or the binding itself failed.
Source
Thrown at ext/node/polyfills/internal/dns/utils.ts:390
return ArrayPrototypePush(newSet, [
ipVersion,
hostIP,
NumberParseInt(port),
]);
}
}
throw new ERR_INVALID_IP_ADDRESS(serv);
});
const errorNumber = this._handle.setServers(newSet);
if (errorNumber !== 0) {
// Reset the servers to the old servers, because ares probably unset them.
this._handle.setServers(ArrayPrototypeJoin(orig, ","));
const err = strerror(errorNumber);
throw new ERR_DNS_SET_SERVERS_FAILED(
err,
ArrayPrototypeToString(servers),
);
}
}
/**
* The resolver instance will send its requests from the specified IP address.
* This allows programs to specify outbound interfaces when used on multi-homed
* systems.
*
* If a v4 or v6 address is not specified, it is set to the default, and the
* operating system will choose a local address automatically.
*
* The resolver will use the v4 local address when making requests to IPv4 DNS
* servers, and the v6 local address when making requests to IPv6 DNS servers.
* The `rrtype` of resolution requests has no impact on the local address used.
*View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Retry with bare IP literals and no ports: setServers(['8.8.8.8', '1.1.1.1']).
- Validate host:port forms (integer port 1-65535) before calling.
- If valid input still fails, capture the servers array and native message and file a Deno issue - that indicates a polyfill/native-layer bug.
Example fix
// before resolver.setServers(['8.8.8.8:0', '1.1.1.1']); // after resolver.setServers(['8.8.8.8', '1.1.1.1']);
Defensive patterns
Strategy: try-catch
Validate before calling
import { isIP } from 'node:net';
function hasValidPorts(servers) {
return servers.every((s) => {
const m = /^\[[0-9a-fA-F:]+\]:(\d+)$/.exec(s) || /^(\d+\.){3}\d+:(\d+)$/.exec(s);
if (!m) return true; // no explicit port
const p = Number(m[1] ?? m[2]);
return Number.isInteger(p) && p >= 1 && p <= 65535;
});
}
if (!hasValidPorts(servers)) throw new TypeError('bad port in DNS server list'); Try / catch
try {
resolver.setServers(servers);
} catch (err) {
if (err?.code === 'ERR_DNS_SET_SERVERS_FAILED') {
logger.error('native layer rejected DNS servers; keeping previous config', err.message);
// the polyfill already restored the old server list
} else {
throw err;
}
} Prevention
- Keep it simple: pass bare IP literals without ports when possible.
- Snapshot getServers() before setServers so you can report or restore config on failure.
- Treat setServers as a fallible config operation: validate input, log failures, keep the process alive.
When it happens
Trigger: Ports that are 0, fractional or out of range ('8.8.8.8:0', '8.8.8.8:99999'); mixed or exotic tuple formats the native layer refuses; reconfiguring while a previous setServers failure left state behind.
Common situations: Dynamic DNS reconfiguration from loosely-validated config; feeding getServers() output round-tripped through JSON or string joins back into setServers; native binding edge cases in the polyfill.
Related errors
- ERR_INVALID_IP_ADDRESS
- The url passed into 'proxy.url' has an invalid scheme for th
- ERR_OUT_OF_RANGE
- ERR_TLS_PROTOCOL_VERSION_CONFLICT
- ERR_TLS_INVALID_PROTOCOL_VERSION
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/f4c4db3101cf7a95.
Report an issue: GitHub.