usebruno/bruno · error · RangeError

The "size" argument must be >= 0

Error message

The "size" argument must be >= 0

What it means

Thrown by the QuickJS sandbox crypto shim for crypto.randomBytes when `size` is a number but negative. Equivalent to Node.js's ERR_OUT_OF_RANGE check. The shim truncates to an integer first (Math.trunc) before the comparison, so -0.5 also trips it.

Source

Thrown at packages/bruno-js/src/sandbox/quickjs/shims/lib/crypto-utils.js:21

const { serializeTypedArray, deserializeTypedArray } = require('./utils');

/**
 * Node.js crypto module shim for QuickJS sandbox
 * Implements crypto.randomBytes and crypto.getRandomValues functions
 */
const addCryptoUtilsShimToContext = async (vm) => {
  let randomBytesHandle = vm.newFunction('randomBytes', function (sizeHandle) {
    try {
      let size = vm.dump(sizeHandle);

      if (typeof size !== 'number') {
        throw new TypeError('The "size" argument must be of type number');
      }

      size = Math.trunc(size);

      if (size < 0) {
        throw new RangeError('The "size" argument must be >= 0');
      }

      if (size > 65536) { // 2^31 - 1 (max safe integer for practical use)
        throw new RangeError('The "size" argument is too large');
      }

      if (size === 0) {
        return marshallToVm([], vm);
      }

      const buffer = crypto.randomBytes(size);

      const byteArray = Array.from(buffer);

      return marshallToVm(byteArray, vm);
    } catch (error) {
      const vmError = vm.newError(error.message);
      vm.setProp(vmError, 'name', vm.newString(error.name));

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Clamp to zero minimum: `crypto.randomBytes(Math.max(0, size))`.
  2. Debug where the negative value originates — log size before the call.
  3. Validate upstream: if size < 0, return early or throw a clearer domain error.

Example fix

// before
const n = end - start; // can be negative
const b = crypto.randomBytes(n);

// after
if (end < start) throw new Error('end must be >= start');
const b = crypto.randomBytes(end - start);
Defensive patterns

Strategy: validation

Validate before calling

function safeRandomBytes(size) {
  const n = Math.trunc(Number(size));
  if (!(n >= 0)) throw new RangeError('size must be >= 0');
  return crypto.randomBytes(n);
}

Type guard

const isNonNegativeInt = (v) => Number.isInteger(v) && v >= 0;

Try / catch

try { crypto.randomBytes(n); }
catch (err) {
  if (/must be >= 0/.test(err.message)) { crypto.randomBytes(Math.max(0, n)); }
  else throw err;
}

Prevention

When it happens

Trigger: Passing a negative length to crypto.randomBytes inside a QuickJS-sandboxed script — e.g. size derived from a subtraction that underflows, or a loop bound computed from a missing/zero field.

Common situations: Buffer length computed as `a - b` where b > a; off-by-one in slicing that yields a negative count; reading a length from a response where the field is absent and defaults to -1.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/10d1fa6105353d06. Report an issue: GitHub.