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 lengthView on GitHub (pinned to 1a708ee577)
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.
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
- Clamp externally-derived sizes before calling randomBytes().
- For >4096 bytes, loop and concatenate.
- Always check Number.isInteger on computed sizes.
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.