{"record":{"id":"fdefa2078c45351c","repo":"agalwood/Motrix","slug":"key-must-be-16-bytes-got-key-length","errorCode":null,"errorMessage":"Key must be 16 bytes, got ${key.length}","messagePattern":"Key must be 16 bytes, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/media/segment-decryptor.ts","lineNumber":29,"sourceCode":"    if (fetchKey) {\n      this.defaultFetchKey = fetchKey\n    } else {\n      this.defaultFetchKey = async (uri: string) => {\n        const response = await fetch(uri)\n        const buffer = await response.arrayBuffer()\n        const key = new Uint8Array(buffer)\n        if (key.length !== 16) {\n          throw new Error(`Key must be 16 bytes, got ${key.length} from ${uri}`)\n        }\n        return key\n      }\n    }\n  }\n\n  decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array {\n    // Validate key and IV lengths\n    if (key.length !== 16) {\n      throw new Error(`Key must be 16 bytes, got ${key.length}`)\n    }\n    if (iv.length !== 16) {\n      throw new Error(`IV must be 16 bytes, got ${iv.length}`)\n    }\n\n    // Convert Uint8Array to Buffer for crypto operations\n    const keyBuffer = Buffer.from(key)\n    const ivBuffer = Buffer.from(iv)\n    const ciphertextBuffer = Buffer.from(ciphertext)\n\n    // Try with PKCS7 auto-padding first\n    try {\n      const decipher = createDecipheriv('aes-128-cbc', keyBuffer, ivBuffer)\n      const plaintext = Buffer.concat([\n        decipher.update(ciphertextBuffer),\n        decipher.final(),\n      ])\n      return new Uint8Array(plaintext)","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/media/segment-decryptor.ts#L11-L47","documentation":"Plain Error thrown by SegmentDecryptor.decrypt when the key argument is not exactly 16 bytes. This guards the public decrypt API (not the fetcher) against callers passing a wrong-size key buffer — a programming error rather than a network one, since decrypt has no URI context to report.","triggerScenarios":"Calling decryptor.decrypt(ciphertext, key, iv) where key.length !== 16. Typical when a 24/32-byte AES-192/256 key is passed, when a hex/base64 string was not decoded, or when a subarray view was sliced incorrectly.","commonSituations":"Caller stored the key as a hex string and forgot to decode; key derived with a different KDF salt/length; off-by-one in Buffer.subarray;混淆 of key and IV variables at the call site.","solutions":["At the call site, assert key.length === 16 before decrypt to get a clearer stack trace.","Confirm the key source: AES-128 keys are 16 bytes; if you have a 32-byte key you need AES-256, not this decryptor.","If the key is hex/base64 encoded, decode it (Buffer.from(k, 'hex'|'base64')) before passing.","Check for accidental string-vs-Buffer confusion — passing the string form of a key makes length = 32 (hex) or more."],"exampleFix":"// before\ndecryptor.decrypt(seg, keyFromString, iv) // keyFromString is 32 chars\n// after\nconst key = Buffer.from(keyFromString, 'hex') // 16 bytes\ndecryptor.decrypt(seg, new Uint8Array(key), iv)","handlingStrategy":"validation","validationCode":"function isAes128Key(key: Uint8Array): boolean {\n  return key.length === 16\n}\nif (!isAes128Key(key)) {\n  throw new Error(`key must be 16 bytes; got ${key.length}`)\n}\ndecryptor.decrypt(ciphertext, key, iv)","typeGuard":"function isAes128Key(key: Uint8Array): boolean {\n  return key instanceof Uint8Array && key.length === 16\n}","tryCatchPattern":"try {\n  decryptor.decrypt(ciphertext, key, iv)\n} catch (e) {\n  if (/Key must be 16 bytes/.test(String(e))) {\n    // re-derive the key (decode hex/base64, or fetch the right one)\n  } else throw e\n}","preventionTips":["Decode hex/base64 key strings to a 16-byte Uint8Array at the boundary.","Use a branded type (e.g. type Aes128Key = Uint8Array & { __brand: 'Aes128Key' }) to force a constructor that validates length.","Never pass raw string keys to decrypt."],"tags":["media","encryption","aes","validation","typescript"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}