agalwood/Motrix · error

randomBytes: n out of range (1..max 4096, got ${n})

Error message

randomBytes: n out of range (1..max 4096, got ${n})

What it means

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:`.

Source

Thrown at src/core/plugin/capabilities/crypto.ts:69

      .digest()
    return Promise.resolve(toUint8Array(buf))
  }

  hmac(
    alg: HashAlg,
    key: Uint8Array,
    input: string | Uint8Array
  ): Promise<Uint8Array> {
    const buf = createHmac(alg, key as Buffer)
      .update(input as Buffer)
      .digest()
    return Promise.resolve(toUint8Array(buf))
  }

  /** Synchronous. Range: 1..4096 inclusive. */
  randomBytes(n: number): Uint8Array {
    if (n < 1 || n > 4096) {
      throw new Error(`randomBytes: n out of range (1..max 4096, got ${n})`)
    }
    return toUint8Array(nodeRandomBytes(n))
  }

  aes(p: AesParams): Promise<Uint8Array> {
    const { mode, op, key, iv, data } = p

    // Validate key length
    const keyLen = key.byteLength
    if (keyLen !== 16 && keyLen !== 32) {
      return Promise.reject(
        new Error(`aes: key must be 16 or 32 bytes, got ${keyLen}`)
      )
    }
    const bits = keyLen === 16 ? 128 : 256
    const algo = `aes-${bits}-${mode}` as const

    // Validate IV length

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Clamp the argument: `const n = Math.max(1, Math.min(4096, requested))` and reject/validate earlier if requested is invalid.
  2. If you genuinely need >4096 bytes, loop and concatenate multiple randomBytes(4096) calls.
  3. Validate that the input is a finite integer before calling (guard against NaN/Infinity).
  4. Surface a clearer upstream error to your caller instead of letting the library's generic message propagate.

Example fix

// before
const nonce = crypto.randomBytes(userSuppliedLen) // throws if 0 or >4096

// after
function safeRandom(n: number): Uint8Array {
  if (!Number.isInteger(n) || n < 1 || n > 4096) {
    throw new RangeError(`nonce length must be 1..4096, got ${n}`)
  }
  return crypto.randomBytes(n)
}
const nonce = safeRandom(userSuppliedLen)
Defensive patterns

Strategy: validation

Validate before calling

function assertRandomSize(n: number): void {
  if (!Number.isInteger(n) || n < 1 || n > 4096) {
    throw new RangeError(`randomBytes size must be an integer in 1..4096, got ${n}`)
  }
}

Type guard

function isRandomBytesRangeError(e: unknown): boolean {
  return e instanceof Error && e.message.startsWith('randomBytes:')
}

Try / catch

try {
  const b = crypto.randomBytes(n)
} catch (e) {
  if (isRandomBytesRangeError(e)) { /* clamp and retry, or reject upstream */ }
  else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/9aad2222d4c9249f. Report an issue: GitHub.