denoland/deno · error · TypeError

Invalid port (expected number)

Error message

Invalid port (expected number): ${maybePort}

What it means

validatePort() accepts only number or numeric-string ports; any other type — undefined/null from clients, booleans, objects, arrays — throws TypeError(`Invalid port (expected number): <value>`). Server-side listen() maps missing null/undefined to port 0 (OS-assigned), so this fires chiefly on connect paths and on structurally wrong values; the printed value usually pinpoints the bad field.

Solutions

  1. Coerce once at the edge: const port = Number(cfg.port ?? 8080).
  2. Inspect the value in the error message — '[object Object]' or 'undefined' identifies the mis-wired property; fix the property path.
  3. Validate with a shared isPort helper before any connect/listen call.

Example fix

// before
Deno.connect({ hostname: "db", port: config.db }); // config.db = { host, port: 5432 }

// after
Deno.connect({ hostname: config.db.host, port: Number(config.db.port) });
Defensive patterns

Strategy: validation

Validate before calling

function toPort(v: unknown, fallback?: number): number {
  if (v === null || v === undefined || v === "") {
    if (fallback === undefined) throw new TypeError("port missing");
    return fallback;
  }
  const n = Number(v);
  if (!Number.isInteger(n) || n < 1 || n > 65535) {
    throw new TypeError(`invalid port: ${String(v)}`);
  }
  return n;
}
Deno.connect({ hostname, port: toPort(cfg.port, 5432) });

Type guard

const isPortLike = (v: unknown): v is number | string =>
  typeof v === "number" || typeof v === "string";

Prevention

When it happens

Trigger: `Deno.connect({ port: undefined })`; port: true; port: { port: 8080 } (double-nested config); passing the whole options object where only the port number was expected; an array from splitting a host string.

Common situations: Config typos like options.port.port; env parsing that yields undefined; destructuring the wrong property; defaults applied at the wrong layer so the port slot receives an object or boolean.

Related errors


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

Appendix: source

Thrown at ext/net/01_net.js:645

    }
    case "tunnel": {
      const { 0: rid, 1: addr } = op_net_listen_tunnel();
      return new Listener(rid, addr, "tunnel");
    }
    default:
      throw new TypeError(`Unsupported transport: '${transport}'`);
  }
}

function validatePort(maybePort, isServer = false) {
  // A missing port means "any available port" (port 0) for servers. Clients
  // must always specify a port to connect to, so a missing port is left as-is
  // and rejected below.
  if (isServer && (maybePort === null || maybePort === undefined)) {
    maybePort = 0;
  }
  if (typeof maybePort !== "number" && typeof maybePort !== "string") {
    throw new TypeError(`Invalid port (expected number): ${maybePort}`);
  }
  if (maybePort === "") throw new TypeError("Invalid port: ''");
  const port = Number(maybePort);
  if (!NumberIsInteger(port)) {
    if (NumberIsNaN(port) && !NumberIsNaN(maybePort)) {
      throw new TypeError(`Invalid port: '${maybePort}'`);
    } else {
      throw new TypeError(`Invalid port: ${maybePort}`);
    }
  } else if (port < (isServer ? 0 : 1) || port > 65535) {
    // Servers may bind to port 0 (OS-assigned), clients may not connect to it.
    throw new RangeError(`Invalid port (out of range): ${maybePort}`);
  }
  return port;
}

function createListenDatagram(udpOpFn, unixOpFn) {
  return function listenDatagram(args) {

View on GitHub (pinned to 9ad36f7a2c)