denoland/deno · error · Error

ERR_TLS_REQUIRED_SERVER_NAME

ERR_TLS_REQUIRED_SERVER_NAME

Error message

"servername" is required parameter for Server.addContext

What it means

Server.prototype.addContext(servername, context) registers an SNI-specific SecureContext for the given hostname; servername is the routing key, so it must be truthy (ext/node/polyfills/_tls_wrap.js:1501). Passing '', null, or undefined throws ERR_TLS_REQUIRED_SERVER_NAME before the [servername, context] pair is pushed to this._contexts.

Source

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

    key: options.key,
    maxVersion: options.maxVersion ?? defaults?.maxVersion,
    minVersion: options.minVersion ?? defaults?.minVersion,
    passphrase: options.passphrase,
    pfx: options.pfx,
    privateKeyEngine: options.privateKeyEngine,
    privateKeyIdentifier: options.privateKeyIdentifier,
    secureOptions: options.secureOptions,
    secureProtocol: options.secureProtocol,
    sessionIdContext: options.sessionIdContext,
    sessionTimeout: options.sessionTimeout,
    sigalgs: options.sigalgs,
    ticketKeys: options.ticketKeys,
  });
};

Server.prototype.addContext = function (servername, context) {
  if (!servername) {
    throw new ERR_TLS_REQUIRED_SERVER_NAME();
  }
  ArrayPrototypePush(this._contexts, [servername, context]);
};

Server.prototype.getTicketKeys = function getTicketKeys() {
  return Buffer.from(this._ticketKeys);
};

Server.prototype.setTicketKeys = function setTicketKeys(keys) {
  if (!isArrayBufferView(keys)) {
    throw new ERR_INVALID_ARG_TYPE(
      "keys",
      ["Buffer", "TypedArray", "DataView"],
      keys,
    );
  }
  if (getViewByteLength(keys) !== 48) {
    throw new Error("Session ticket keys must be a 48-byte buffer");

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Check the domain is a non-empty string before registering: if (!servername) continue or throw a config error
  2. Validate your certificate map entries at startup and report the offending entry instead of crashing inside addContext
  3. Pass the plain hostname ('example.com'), not a URL or wildcard with protocol

Example fix

// before
for (const [domain, cfg] of Object.entries(certs)) {
  server.addContext(domain, tls.createSecureContext(cfg)); // domain may be ''
}

// after
for (const [domain, cfg] of Object.entries(certs)) {
  if (typeof domain !== 'string' || domain === '') continue;
  server.addContext(domain, tls.createSecureContext(cfg));
}
Defensive patterns

Strategy: validation

Validate before calling

if (!servername || typeof servername !== 'string') throw new Error('addContext requires a non-empty servername');

Type guard

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

Try / catch

try { server.addContext(servername, ctx); } catch (e) { if (e.code === 'ERR_TLS_REQUIRED_SERVER_NAME') { /* skip or log bad vhost entry */ } else throw e; }

Prevention

When it happens

Trigger: server.addContext('', ctx) with an empty string; addContext(hostFromConfig) where the config entry lacked the host field (undefined); addContext(0) or other falsy coerced values.

Common situations: Looping over a certificate map (e.g. { 'example.com': { cert, key } }) and hitting an empty/missing key; loading vhost configs where one entry has no domain; refactoring code that previously passed the domain via a variable that is now unset.

Understand the failure class

Related errors


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