{"record":{"id":"ced24167fe27c792","repo":"usebruno/bruno","slug":"the-size-argument-must-be-of-type-number","errorCode":null,"errorMessage":"The \"size\" argument must be of type number","messagePattern":"The \"size\" argument must be of type number","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/bruno-js/src/sandbox/quickjs/shims/lib/crypto-utils.js","lineNumber":15,"sourceCode":"const crypto = require('node:crypto');\nconst { marshallToVm } = require('../../utils');\nconst { 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","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-js/src/sandbox/quickjs/shims/lib/crypto-utils.js#L1-L33","documentation":"Thrown by the QuickJS sandbox crypto shim for crypto.randomBytes when the `size` argument passed from sandbox code is not a JavaScript number (e.g. a string, undefined, null, boolean, object). It mirrors Node.js's built-in ERR_INVALID_ARG_TYPE check for the same API.","triggerScenarios":"Calling crypto.randomBytes(undefined), crypto.randomBytes('16'), crypto.randomBytes(null), or passing a variable that was never assigned a numeric value inside a QuickJS-sandboxed Bru script.","commonSituations":"Size comes from bru.getVar() (returns a string) and is fed straight to randomBytes; an optional function parameter defaults to undefined; parseInt/Number coercion was forgotten before the call.","solutions":["Coerce the argument explicitly: `crypto.randomBytes(Number(size))` or `crypto.randomBytes(parseInt(size, 10))`.","Guard against undefined/null before calling: `if (size == null) throw ...`.","If the value comes from a Bruno variable, convert it once when reading: `const size = Number(bru.getVar('tokenSize'))`."],"exampleFix":"// before\nconst bytes = crypto.randomBytes(bru.getVar('size')); // var is a string\n\n// after\nconst bytes = crypto.randomBytes(Number(bru.getVar('size')));","handlingStrategy":"validation","validationCode":"function safeRandomBytes(size) {\n  if (typeof size !== 'number' || Number.isNaN(size)) {\n    throw new TypeError('size must be a number');\n  }\n  return crypto.randomBytes(size);\n}","typeGuard":"const isNumber = (v) => typeof v === 'number' && !Number.isNaN(v);","tryCatchPattern":"try {\n  const b = crypto.randomBytes(maybeString);\n} catch (err) {\n  if (/must be of type number/.test(err.message)) {\n    const b = crypto.randomBytes(Number(maybeString));\n  } else throw err;\n}","preventionTips":["Coerce Bruno variables (always strings) with Number() before passing to crypto.","Default optional sizes to an explicit number, not undefined."],"tags":["bruno-js","quickjs","sandbox","crypto","validation"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}