{"record":{"id":"daa9fcba619ca1fb","repo":"agalwood/Motrix","slug":"iv-must-be-16-bytes-got-iv-length","errorCode":null,"errorMessage":"IV must be 16 bytes, got ${iv.length}","messagePattern":"IV must be 16 bytes, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/media/segment-decryptor.ts","lineNumber":32,"sourceCode":"      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)\n    } catch (err) {\n      // Only fall back if error is PKCS7-padding related\n      const msg = err instanceof Error ? err.message.toLowerCase() : ''","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/media/segment-decryptor.ts#L14-L50","documentation":"Plain Error thrown by SegmentDecryptor.decrypt when the iv argument is not exactly 16 bytes. AES-128-CBC IVs are exactly one block (128 bits = 16 bytes); a different length means the caller built the IV wrong (e.g. used a 32-bit value, an 8-byte uint64, or a hex string).","triggerScenarios":"Calling decryptor.decrypt(ciphertext, key, iv) where iv.length !== 16. Typical when the caller passed a 4-byte sequence number, an 8-byte Buffer from BigInt, or a 32-char hex string instead of the decoded 16-byte form.","commonSituations":"Caller used seqNumberIv correctly elsewhere but built a custom IV wrong here; passed the IV as a hex string; confused the IV with a shorter nonce from another cipher (AES-GCM uses 12-byte nonces); off-by-one subarray slice.","solutions":["Use the provided seqNumberIv(seq) helper to build sequence-number IVs — it always returns 16 bytes.","If you have an explicit IV hex string, decode it: Buffer.from(ivHex.replace(/^0x/, '').padStart(32, '0'), 'hex').","At the call site assert iv.length === 16 for a clearer error before decrypt.","Do not reuse AES-GCM 12-byte nonces for AES-128-CBC — they are different cipher IV shapes."],"exampleFix":"// before — passing an 8-byte bigint IV\ndecryptor.decrypt(seg, key, Buffer.from([...bigIntToBytes(seq, 8)]))\n// after — use the helper that produces a 16-byte IV\nimport { seqNumberIv } from './segment-plan'\ndecryptor.decrypt(seg, key, seqNumberIv(seq))","handlingStrategy":"validation","validationCode":"function isAes128Iv(iv: Uint8Array): boolean {\n  return iv.length === 16\n}\nif (!isAes128Iv(iv)) {\n  throw new Error(`iv must be 16 bytes; got ${iv.length}`)\n}\ndecryptor.decrypt(ciphertext, key, iv)","typeGuard":"function isAes128Iv(iv: Uint8Array): boolean {\n  return iv instanceof Uint8Array && iv.length === 16\n}","tryCatchPattern":"try {\n  decryptor.decrypt(ciphertext, key, iv)\n} catch (e) {\n  if (/IV must be 16 bytes/.test(String(e))) {\n    // rebuild IV via seqNumberIv(seq) or decode hex\n  } else throw e\n}","preventionTips":["Use seqNumberIv(seq) for sequence-based IVs — it always returns 16 bytes.","Decode hex IV strings with the parseIvHex helper or Buffer.from(hex, 'hex') before passing.","Do not conflate AES-GCM 12-byte nonces with AES-CBC 16-byte IVs."],"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"}