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
- Ensure the value is a string before calling: if (typeof name === 'string') tlsSocket.setServername(name)
- Fix the upstream source of the value — usually options.host or options.servername that was never set
- 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
- Pass servername in tls.connect options once instead of calling setServername later
- Type-check values coming from config/env before reuse as hostnames
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
- ERR_TLS_REQUIRED_SERVER_NAME
- Unsupported transport: '${transport}'
- If "keyFormat" is specified, it must be "pem": received "${k
- If `cert` is specified, `key` must be specified as well for
- If `key` is specified, `cert` must be specified as well for
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/35ae536adc9d7ee2.
Report an issue: GitHub.