denoland/deno · error · TypeError
ERR_INVALID_ARG_VALUE
ERR_INVALID_ARG_VALUE
Error message
The property 'options.ticketKeys' must be exactly 48 bytes. Received ${getViewByteLength(options.ticketKeys)} What it means
After options.ticketKeys passes the type check, its byte length must be exactly 48 — the TLS session-ticket key format is 16 bytes name + 16 bytes HMAC key + 16 bytes AES key (ext/node/polyfills/_tls_wrap.js:1407). Any other length throws ERR_INVALID_ARG_VALUE with reason 'must be exactly 48 bytes', matching Node.
Source
Thrown at ext/node/polyfills/_tls_wrap.js:1407
if (options.sessionTimeout != null) {
validateInt32(
options.sessionTimeout,
"options.sessionTimeout",
0,
);
}
if (options.ticketKeys != null) {
if (!isArrayBufferView(options.ticketKeys)) {
throw new ERR_INVALID_ARG_TYPE(
"options.ticketKeys",
["Buffer", "TypedArray", "DataView"],
options.ticketKeys,
);
}
if (getViewByteLength(options.ticketKeys) !== 48) {
throw new ERR_INVALID_ARG_VALUE(
"options.ticketKeys",
getViewByteLength(options.ticketKeys),
"must be exactly 48 bytes",
);
}
}
this._ticketKeys = options.ticketKeys == null
? Buffer.alloc(48)
: Buffer.from(
getViewBuffer(options.ticketKeys),
getViewByteOffset(options.ticketKeys),
getViewByteLength(options.ticketKeys),
);
this.setSecureContext(options);
if (options.handshakeTimeout != null) {
validateNumber(options.handshakeTimeout, "options.handshakeTimeout");View on GitHub (pinned to 89f33cbef2)
Solutions
- Generate exactly 48 bytes: crypto.randomBytes(48)
- Verify length after decoding from hex/base64: buf.length === 48 or throw early with your own message
- If your store holds multiple keys, pass only one 48-byte key per server or rotate via server.setTicketKeys(oneKey)
Example fix
// before
const server = tls.createServer({ ticketKeys: crypto.randomBytes(64) });
// after
const server = tls.createServer({ ticketKeys: crypto.randomBytes(48) }); Defensive patterns
Strategy: validation
Validate before calling
if (opts.ticketKeys != null && opts.ticketKeys.length !== 48) throw new RangeError(`ticketKeys must be 48 bytes, got ${opts.ticketKeys.length}`); Type guard
function is48Bytes(v) { return ArrayBuffer.isView(v) && v.byteLength === 48; } Try / catch
try { tls.createServer(opts); } catch (e) { if (e.code === 'ERR_INVALID_ARG_VALUE' && /48 bytes/.test(e.message)) { delete opts.ticketKeys; /* fall back to generated keys */ return tls.createServer(opts); } throw e; } Prevention
- Generate with crypto.randomBytes(48) and assert length in one line
- Remember hex strings are twice the byte count after decoding
When it happens
Trigger: tls.createServer({ ticketKeys: Buffer.alloc(32) }); hex string decoded to 96 bytes because it was 96 hex chars; base64 blob truncated or padded incorrectly; sharing keys generated for a different library that uses another size.
Common situations: Generating ticket keys with crypto.randomBytes(N) where N != 48; key-rotation pipelines that store keys with a prefix/version byte, making 49 bytes; copying a 'ticket key' that is actually a pair of keys (96 bytes).
Related errors
- Session ticket keys must be a 48-byte buffer
- 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/4030fe8ebd7bd335.
Report an issue: GitHub.