denoland/deno · error · TypeError

ERR_INVALID_IP_ADDRESS

ERR_INVALID_IP_ADDRESS

Error message

Invalid IP address: ${localAddress}

What it means

During net.connect(), _lookupAndConnect validates options.localAddress with isIP(): it must be a local IP literal, because the value is passed straight to bind() — no DNS resolution happens for it. A hostname (even 'localhost') or malformed IP throws ERR_INVALID_IP_ADDRESS before the connection starts.

Source

Thrown at ext/node/polyfills/net.ts:1060

        }

        socket[kBuffer] = userBuf;
      }

      socket._handle.useUserBuffer(userBuf);
    }
  }
}

function _lookupAndConnect(self: Socket, options: TcpSocketConnectOptions) {
  const { localAddress, localPort } = options;
  const host = options.host || "localhost";
  let { port, autoSelectFamilyAttemptTimeout, autoSelectFamily } = options;

  validateStringWithoutNullBytes(host, "options.host");

  if (localAddress && !isIP(localAddress)) {
    throw new ERR_INVALID_IP_ADDRESS(localAddress);
  }

  if (localPort) {
    validateNumber(localPort, "options.localPort");
  }

  if (typeof port !== "undefined") {
    if (typeof port !== "number" && typeof port !== "string") {
      throw new ERR_INVALID_ARG_TYPE(
        "options.port",
        ["number", "string"],
        port,
      );
    }

    validatePort(port);
  }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass an IP literal for localAddress: '127.0.0.1', '10.0.0.5', '::1'
  2. If the source is a hostname, resolve it first with dns.lookup(host) and use the returned address
  3. Pre-validate with net.isIP(localAddress) !== 0 and fall back to default (omit localAddress)

Example fix

// before
net.connect({ port, host, localAddress: cfg.localHost }); // hostname -> throws

// after
const localAddress = net.isIP(cfg.localHost) ? cfg.localHost : undefined;
net.connect({ port, host, localAddress });
Defensive patterns

Strategy: validation

Validate before calling

const localAddress = net.isIP(cfg.localHost ?? '') !== 0
  ? cfg.localHost
  : undefined; // omit rather than pass a hostname
net.connect({ port, host, localAddress });

Type guard

function isIpLiteral(v: unknown): v is string {
  return typeof v === 'string' && net.isIP(v) !== 0;
}

Try / catch

try {
  socket = net.connect({ port, host, localAddress });
} catch (e: any) {
  if (e?.code === 'ERR_INVALID_IP_ADDRESS') {
    socket = net.connect({ port, host }); // retry without localAddress binding
  } else throw e;
}

Prevention

When it happens

Trigger: net.connect({ port, host: 'example.com', localAddress: 'example.com' }); localAddress: 'localhost' (a hostname, not an IP); localAddress: '192.168.1.999'; a config/env var supplying a hostname into localAddress.

Common situations: Multi-homed servers binding egress traffic to a specific NIC by name instead of address; copying the host option's semantics onto localAddress; IPv6 addresses missing or misplaced (e.g. missing brackets does not matter, but a bare zone-id does).

Related errors


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