denoland/deno · error · TypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "name" argument must be of type string. Received ${name}

What it means

TLSSocket.prototype.setServername requires the SNI hostname to be a string (ext/node/polyfills/_tls_wrap.js:1062). Passing a number, null, undefined, or any non-string triggers ERR_INVALID_ARG_TYPE with name 'name' before the value reaches the underlying handle. This is the client-side SNI setter, typically called from a checkServerIdentity or connect callback or by libraries that set the hostname after socket creation.

Source

Thrown at ext/node/polyfills/_tls_wrap.js:1062

    // called (e.g. by net.Socket.resume), we need to stop and restart to
    // pick up the new interceptor callback.
    tcpHandle.readStop();
    tcpHandle.readStart();
  }

  // Kick-start the TLS readable side. During start(), the handshake cycle
  // may have received and processed a close_notify (peer called end() before
  // we set up event listeners). The decrypted EOF is buffered in pending_eof
  // because inner.onread wasn't set yet. Call readStart() directly on the
  // TLSWrap to install onread and flush any pending data/EOF.
  if (this._handle) {
    this._handle.readStart();
  }
};

TLSSocket.prototype.setServername = function (name) {
  if (typeof name !== "string") {
    throw new ERR_INVALID_ARG_TYPE("name", "string", name);
  }
  if (this._tlsOptions?.isServer) {
    throw new ERR_TLS_SNI_FROM_SERVER();
  }
  this._handle?.setServername(name);
};

// Format prefixes for the synthetic session buffers we emit from
// onConnectSecure when rustls handles resumption internally. The encoded
// payload is `${servername ?? host ?? ""}:${port ?? ""}` -- see the
// matching emit sites in onConnectSecure.
const SYNTHETIC_SESSION_PREFIXES = [
  "deno-tls12-session:",
  "deno-tls13-session-ticket-1:",
  "deno-tls13-session-ticket-2:",
  "deno-tls13-dummy-session:",
];

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Ensure the value is a string before calling: if (typeof name === 'string') tlsSocket.setServername(name)
  2. Fix the upstream source of the value — usually options.host or options.servername that was never set
  3. Prefer passing servername in tls.connect({ servername }) so the runtime sets it during handshake instead of calling setServername manually

Example fix

// before
socket.setServername(options.host); // host may be undefined

// after
const servername = typeof options.host === 'string' ? options.host : undefined;
if (servername) socket.setServername(servername);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof name !== 'string' || name === '') throw new TypeError('servername must be a non-empty string');

Type guard

function isServername(v) { return typeof v === 'string' && v.length > 0; }

Try / catch

try { socket.setServername(name); } catch (e) { if (e.code === 'ERR_INVALID_ARG_TYPE') { /* skip SNI, name missing */ } else throw e; }

Prevention

When it happens

Trigger: tlsSocket.setServername(undefined), setServername(host) where host came from URL parsing that produced undefined, or feeding net.isIP-validated values / numbers into it.

Common situations: Code deriving the servername from configuration that may be absent (env var not set, options.host undefined); passing an IP address string is accepted by this check but belongs to a separate validation path; upgrading old code that relied on implicit coercion of numbers or objects to strings.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/35ae536adc9d7ee2. Report an issue: GitHub.