denoland/deno · error · Error

Session ticket keys must be a 48-byte buffer

Error message

Session ticket keys must be a 48-byte buffer

What it means

The second guard in setTicketKeys enforces the TLS session-ticket key size: exactly 48 bytes (16 name + 16 HMAC key + 16 AES key, ext/node/polyfills/_tls_wrap.js:1519). Unlike the constructor path, which throws the coded ERR_INVALID_ARG_VALUE, this runtime-rotation path throws a plain Error('Session ticket keys must be a 48-byte buffer').

Source

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

    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");
  }
  this._ticketKeys = Buffer.from(
    getViewBuffer(keys),
    getViewByteOffset(keys),
    getViewByteLength(keys),
  );
};

// ---------------------------------------------------------------------------
// connect
// ---------------------------------------------------------------------------

function onConnectEnd() {
  if (!this._hadError) {
    const options = this[kConnectOptions];
    this._hadError = true;
    const error = connResetException(
      "Client network socket disconnected " +

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Validate length before rotating: if (keys.length !== 48) throw new Error('bad rotation key')
  2. Generate rotation material with crypto.randomBytes(48) from the same source as initial keys
  3. Check how the secret store encodes keys (hex doubles the byte count) and decode accordingly

Example fix

// before
server.setTicketKeys(Buffer.from(secretManager.get('ticketKeys'), 'utf8'));

// after
const keys = Buffer.from(secretManager.get('ticketKeys'), 'hex');
if (keys.length === 48) server.setTicketKeys(keys);
Defensive patterns

Strategy: validation

Validate before calling

if (keys.length !== 48) throw new RangeError(`ticket keys must be 48 bytes, got ${keys.length}`);

Type guard

function isValidRotationKey(v) { return ArrayBuffer.isView(v) && v.byteLength === 48; }

Try / catch

try { server.setTicketKeys(keys); } catch (e) { if (/48-byte buffer/.test(e.message)) { /* keep old keys, alert rotation pipeline */ } else throw e; }

Prevention

When it happens

Trigger: server.setTicketKeys(Buffer.alloc(47)); rotating with a key blob whose hex decoded to 96 bytes (two keys concatenated); rotation pipeline that appends a key-id byte, yielding 49.

Common situations: Automated key rotation where new material is generated with a different length than the original; copying ticket key formats from other TLS stacks that use 32- or 80-byte keys; test fixtures with arbitrary-length buffers.

Related errors


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