{"record":{"id":"9aad2222d4c9249f","repo":"agalwood/Motrix","slug":"randombytes-n-out-of-range-1-max-4096-got-n","errorCode":null,"errorMessage":"randomBytes: n out of range (1..max 4096, got ${n})","messagePattern":"randomBytes: n out of range \\(1\\.\\.max 4096, got (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/plugin/capabilities/crypto.ts","lineNumber":69,"sourceCode":"      .digest()\n    return Promise.resolve(toUint8Array(buf))\n  }\n\n  hmac(\n    alg: HashAlg,\n    key: Uint8Array,\n    input: string | Uint8Array\n  ): Promise<Uint8Array> {\n    const buf = createHmac(alg, key as Buffer)\n      .update(input as Buffer)\n      .digest()\n    return Promise.resolve(toUint8Array(buf))\n  }\n\n  /** Synchronous. Range: 1..4096 inclusive. */\n  randomBytes(n: number): Uint8Array {\n    if (n < 1 || n > 4096) {\n      throw new Error(`randomBytes: n out of range (1..max 4096, got ${n})`)\n    }\n    return toUint8Array(nodeRandomBytes(n))\n  }\n\n  aes(p: AesParams): Promise<Uint8Array> {\n    const { mode, op, key, iv, data } = p\n\n    // Validate key length\n    const keyLen = key.byteLength\n    if (keyLen !== 16 && keyLen !== 32) {\n      return Promise.reject(\n        new Error(`aes: key must be 16 or 32 bytes, got ${keyLen}`)\n      )\n    }\n    const bits = keyLen === 16 ? 128 : 256\n    const algo = `aes-${bits}-${mode}` as const\n\n    // Validate IV length","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/crypto.ts#L51-L87","documentation":"Thrown by the crypto capability's synchronous `randomBytes(n)` when `n < 1` or `n > 4096`. The implementation caps at 4096 bytes per call to bound memory and CPU; the documented range is 1..4096 inclusive. Unlike most errors in this module it is a plain `Error` (no custom code), so callers narrowing by message must check the prefix `randomBytes:`.","triggerScenarios":"Passing 0, a negative number, NaN, or a value greater than 4096 to randomBytes(). Common with computed sizes from untrusted input, e.g. `randomBytes(userLen)` where userLen came from a request body or config without bounds-checking.","commonSituations":"Plugin computes a token length from external input and forgets to clamp; porting code from a crypto API with a higher/none cap (e.g. Node's crypto.randomBytes accepts large n); off-by-one where a 0 sneaks through on empty input.","solutions":["Clamp the argument: `const n = Math.max(1, Math.min(4096, requested))` and reject/validate earlier if requested is invalid.","If you genuinely need >4096 bytes, loop and concatenate multiple randomBytes(4096) calls.","Validate that the input is a finite integer before calling (guard against NaN/Infinity).","Surface a clearer upstream error to your caller instead of letting the library's generic message propagate."],"exampleFix":"// before\nconst nonce = crypto.randomBytes(userSuppliedLen) // throws if 0 or >4096\n\n// after\nfunction safeRandom(n: number): Uint8Array {\n  if (!Number.isInteger(n) || n < 1 || n > 4096) {\n    throw new RangeError(`nonce length must be 1..4096, got ${n}`)\n  }\n  return crypto.randomBytes(n)\n}\nconst nonce = safeRandom(userSuppliedLen)","handlingStrategy":"validation","validationCode":"function assertRandomSize(n: number): void {\n  if (!Number.isInteger(n) || n < 1 || n > 4096) {\n    throw new RangeError(`randomBytes size must be an integer in 1..4096, got ${n}`)\n  }\n}","typeGuard":"function isRandomBytesRangeError(e: unknown): boolean {\n  return e instanceof Error && e.message.startsWith('randomBytes:')\n}","tryCatchPattern":"try {\n  const b = crypto.randomBytes(n)\n} catch (e) {\n  if (isRandomBytesRangeError(e)) { /* clamp and retry, or reject upstream */ }\n  else throw e\n}","preventionTips":["Clamp externally-derived sizes before calling randomBytes().","For >4096 bytes, loop and concatenate.","Always check Number.isInteger on computed sizes."],"tags":["crypto","random","input-validation","ranges"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}