denoland/deno · error · TypeError

ERR_INVALID_IP_ADDRESS

ERR_INVALID_IP_ADDRESS

Error message

Invalid IP address: ${serv}

What it means

Resolver.setServers() parses each entry as an IP literal with an optional port (bracketed [v6]:port form included); the address part must pass isIP(). An entry whose address is not an IP literal throws ERR_INVALID_IP_ADDRESS naming the offending entry - hostnames and URLs are rejected because the resolver needs concrete addresses.

Source

Thrown at ext/node/polyfills/internal/dns/utils.ts:380

      // addr::port
      const addrSplitMatch = StringPrototypeMatch(serv, addrSplitRE);

      if (addrSplitMatch) {
        const hostIP = addrSplitMatch[1];
        const port = addrSplitMatch[2] || `${IANA_DNS_PORT}`;

        ipVersion = isIP(hostIP);

        if (ipVersion !== 0) {
          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.

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use IP literals: ['8.8.8.8', '1.1.1.1', '[2001:4860:4860::8888]:53'].
  2. Resolve provider hostnames once at startup and feed the resulting IPs.
  3. Validate every entry (IP literal, port 1-65535) before calling setServers.

Example fix

// before
resolver.setServers(['dns.google', 'https://1.1.1.1/dns-query']);

// after
resolver.setServers(['8.8.8.8', '1.1.1.1', '[2001:4860:4860::8888]:53']);
Defensive patterns

Strategy: validation

Validate before calling

import { isIP } from 'node:net';

function looksLikeServer(s) {
  if (/^\[[0-9a-fA-F:]+\](:\d+)?$/.test(s)) return true;      // [ipv6] or [ipv6]:port
  if (/^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/.test(s)) return true; // ipv4 or ipv4:port
  return isIP(s) !== 0;                                       // bare ipv6
}
const servers = configured.filter(looksLikeServer);
if (servers.length) resolver.setServers(servers);

Try / catch

try {
  resolver.setServers(servers);
} catch (err) {
  if (err?.code === 'ERR_INVALID_IP_ADDRESS') {
    logger.warn('invalid DNS server entry; keeping defaults', err.message);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: resolver.setServers(['dns.google']) (hostname); ['localhost:53']; ['https://1.1.1.1/dns-query'] (DoH URL); a malformed literal like '192.168.0'.

Common situations: Wanting DoH-style resolver names where only IPs work; DNS config scraped from systemd-resolved, docker or k8s templates that contain hostnames; env-var lists with typos.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/088bb72963243947. Report an issue: GitHub.