denoland/deno · error · TypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "options.port" property must be one of type number or string

What it means

In net.connect()'s connect path, once options.port is defined it must be a number or a string (numeric string); validatePort and the port |= 0 truncation follow. Any other type throws ERR_INVALID_ARG_TYPE — notably null (typeof null === 'object'), plain objects, booleans, and BigInts.

Source

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

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);
  }

  port |= 0;

  if (autoSelectFamily != null) {
    validateBoolean(autoSelectFamily, "options.autoSelectFamily");
  } else {
    autoSelectFamily = autoSelectFamilyDefault;
  }

  if (autoSelectFamilyAttemptTimeout !== undefined) {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Normalize before connecting: const port = rawPort ?? DEFAULT_PORT; net.connect({ port: Number(port) })
  2. Validate the type at the config boundary: reject port values that are neither number nor numeric string
  3. Use undefined (omit the field) when there is no port, never null

Example fix

// before
net.connect({ port: config.port, host }); // config.port === null -> throws

// after
net.connect({
  port: config.port == null ? DEFAULT_PORT : Number(config.port),
  host,
});
Defensive patterns

Strategy: validation

Validate before calling

if (port !== undefined && typeof port !== 'number' && typeof port !== 'string') {
  throw new TypeError(`options.port must be number|string, got ${typeof port}`);
}
net.connect({ port: port == null ? DEFAULT_PORT : Number(port), host });

Type guard

function isValidPortValue(v: unknown): v is number | string | undefined {
  return v === undefined || typeof v === 'number' || typeof v === 'string';
}

Try / catch

try {
  socket = net.connect({ port, host });
} catch (e: any) {
  if (e?.code === 'ERR_INVALID_ARG_TYPE' && /options\.port/.test(e.message)) {
    socket = net.connect({ port: DEFAULT_PORT, host });
  } else throw e;
}

Prevention

When it happens

Trigger: net.connect({ port: null }) from an optional config field defaulting to null; port: {} after wrong destructuring; port: true from a flag; port: 8080n (BigInt) — strings like '3000' are fine, undefined skips the check.

Common situations: JSON/YAML configs where an absent port serializes as null instead of undefined; TypeScript code assuming optional number but receiving null at runtime from an API response; env parsing that yields objects on failure.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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