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
- Check the domain is a non-empty string before registering: if (!servername) continue or throw a config error
- Validate your certificate map entries at startup and report the offending entry instead of crashing inside addContext
- 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
- Validate certificate-map entries at startup and reject config with missing domains
- Pass bare hostnames, not URLs
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- A key and certificate are required for `Deno.listenTls`
- ERR_INVALID_ARG_TYPE
- ERR_TLS_SNI_FROM_SERVER
- Unsupported transport: '${transport}'
- If "keyFormat" is specified, it must be "pem": received "${k
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/ed2ef0d64a451d3c.
Report an issue: GitHub.