{"record":{"id":"10d1fa6105353d06","repo":"usebruno/bruno","slug":"the-size-argument-must-be-0","errorCode":null,"errorMessage":"The \"size\" argument must be >= 0","messagePattern":"The \"size\" argument must be >= 0","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/bruno-js/src/sandbox/quickjs/shims/lib/crypto-utils.js","lineNumber":21,"sourceCode":"const { serializeTypedArray, deserializeTypedArray } = require('./utils');\n\n/**\n * Node.js crypto module shim for QuickJS sandbox\n * Implements crypto.randomBytes and crypto.getRandomValues functions\n */\nconst addCryptoUtilsShimToContext = async (vm) => {\n  let randomBytesHandle = vm.newFunction('randomBytes', function (sizeHandle) {\n    try {\n      let size = vm.dump(sizeHandle);\n\n      if (typeof size !== 'number') {\n        throw new TypeError('The \"size\" argument must be of type number');\n      }\n\n      size = Math.trunc(size);\n\n      if (size < 0) {\n        throw new RangeError('The \"size\" argument must be >= 0');\n      }\n\n      if (size > 65536) { // 2^31 - 1 (max safe integer for practical use)\n        throw new RangeError('The \"size\" argument is too large');\n      }\n\n      if (size === 0) {\n        return marshallToVm([], vm);\n      }\n\n      const buffer = crypto.randomBytes(size);\n\n      const byteArray = Array.from(buffer);\n\n      return marshallToVm(byteArray, vm);\n    } catch (error) {\n      const vmError = vm.newError(error.message);\n      vm.setProp(vmError, 'name', vm.newString(error.name));","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-js/src/sandbox/quickjs/shims/lib/crypto-utils.js#L3-L39","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clamp to zero minimum: `crypto.randomBytes(Math.max(0, size))`.","Debug where the negative value originates — log size before the call.","Validate upstream: if size < 0, return early or throw a clearer domain error."],"exampleFix":"// before\nconst n = end - start; // can be negative\nconst b = crypto.randomBytes(n);\n\n// after\nif (end < start) throw new Error('end must be >= start');\nconst b = crypto.randomBytes(end - start);","handlingStrategy":"validation","validationCode":"function safeRandomBytes(size) {\n  const n = Math.trunc(Number(size));\n  if (!(n >= 0)) throw new RangeError('size must be >= 0');\n  return crypto.randomBytes(n);\n}","typeGuard":"const isNonNegativeInt = (v) => Number.isInteger(v) && v >= 0;","tryCatchPattern":"try { crypto.randomBytes(n); }\ncatch (err) {\n  if (/must be >= 0/.test(err.message)) { crypto.randomBytes(Math.max(0, n)); }\n  else throw err;\n}","preventionTips":["Clamp computed lengths with Math.max(0, x).","Validate upstream arithmetic that produces buffer lengths."],"tags":["bruno-js","quickjs","sandbox","crypto","validation","range"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}