{"record":{"id":"4030fe8ebd7bd335","repo":"denoland/deno","slug":"err-invalid-arg-value-4030fe","errorCode":"ERR_INVALID_ARG_VALUE","errorMessage":"The property 'options.ticketKeys' must be exactly 48 bytes. Received ${getViewByteLength(options.ticketKeys)}","messagePattern":"The property 'options\\.ticketKeys' must be exactly 48 bytes\\. Received (.+?)","errorType":"error_code","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_tls_wrap.js","lineNumber":1407,"sourceCode":"\n  if (options.sessionTimeout != null) {\n    validateInt32(\n      options.sessionTimeout,\n      \"options.sessionTimeout\",\n      0,\n    );\n  }\n\n  if (options.ticketKeys != null) {\n    if (!isArrayBufferView(options.ticketKeys)) {\n      throw new ERR_INVALID_ARG_TYPE(\n        \"options.ticketKeys\",\n        [\"Buffer\", \"TypedArray\", \"DataView\"],\n        options.ticketKeys,\n      );\n    }\n    if (getViewByteLength(options.ticketKeys) !== 48) {\n      throw new ERR_INVALID_ARG_VALUE(\n        \"options.ticketKeys\",\n        getViewByteLength(options.ticketKeys),\n        \"must be exactly 48 bytes\",\n      );\n    }\n  }\n  this._ticketKeys = options.ticketKeys == null\n    ? Buffer.alloc(48)\n    : Buffer.from(\n      getViewBuffer(options.ticketKeys),\n      getViewByteOffset(options.ticketKeys),\n      getViewByteLength(options.ticketKeys),\n    );\n\n  this.setSecureContext(options);\n\n  if (options.handshakeTimeout != null) {\n    validateNumber(options.handshakeTimeout, \"options.handshakeTimeout\");","sourceCodeStart":1389,"sourceCodeEnd":1425,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_tls_wrap.js#L1389-L1425","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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)"],"exampleFix":"// before\nconst server = tls.createServer({ ticketKeys: crypto.randomBytes(64) });\n\n// after\nconst server = tls.createServer({ ticketKeys: crypto.randomBytes(48) });","handlingStrategy":"validation","validationCode":"if (opts.ticketKeys != null && opts.ticketKeys.length !== 48) throw new RangeError(`ticketKeys must be 48 bytes, got ${opts.ticketKeys.length}`);","typeGuard":"function is48Bytes(v) { return ArrayBuffer.isView(v) && v.byteLength === 48; }","tryCatchPattern":"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; }","preventionTips":["Generate with crypto.randomBytes(48) and assert length in one line","Remember hex strings are twice the byte count after decoding"],"tags":["tls","session-resumption","tickets","validation","length"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}