{"record":{"id":"212fa550ca924785","repo":"ai/nanoid","slug":"wrong-id-size","errorCode":null,"errorMessage":"Wrong ID size","messagePattern":"Wrong ID size","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"index.js","lineNumber":21,"sourceCode":"export { urlAlphabet }\n\n// `crypto.getRandomValues` rejects requests over 65536 bytes,\n// so bigger buffers are filled by chunks.\nconst GET_RANDOM_LIMIT = 65536\n\nfunction fillRandom(buffer) {\n  let from = 0\n  while (from < buffer.length) {\n    let to = Math.min(from + GET_RANDOM_LIMIT, buffer.length)\n    crypto.getRandomValues(buffer.subarray(from, to))\n    from = to\n  }\n}\n\nexport function random(bytes) {\n  // `|=` convert `bytes` to number to prevent `valueOf` abusing\n  bytes |= 0\n  if (bytes < 0) throw new RangeError('Wrong ID size')\n  // `random()` is used rarely and not in hot paths, so it makes\n  // a direct crypto call instead of using a byte pool.\n  let buffer = Buffer.allocUnsafe(bytes)\n  fillRandom(buffer)\n  return buffer\n}\n\nexport function customRandom(alphabet, defaultSize, getRandom) {\n  // Random bytes are 0-255. `random % alphabet.length` can waste\n  // that entropy by making some symbols more likely.\n  //\n  // `safeByteCutoff` will be divided by `alphabet.length` without remainder\n  // fixing issue of broken distribution.\n  //\n  // Example: with 17 symbols, `safeByteCutoff` is 255.\n  // Bytes 0-254 preserve entropy evenly: each symbol gets 15 source bytes.\n  // Byte 255 would map to `0` again, making one symbol slightly more likely.\n  // So we reject 255.","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/ai/nanoid/blob/07a39d62d84c21af5046fe6b2ef7b3e36ee557db/index.js#L3-L39","documentation":"nanoid's `random(bytes)` coerces the requested byte count with `bytes |= 0` and throws a RangeError when the result is negative. This guards against NaN/negative/non-numeric inputs (and `valueOf` abuse) reaching `Buffer.allocUnsafe`, which would otherwise throw an opaque Node error. It means the size argument you passed to `random()` is not a valid non-negative integer.","triggerScenarios":"Calling `random(-5)` directly; passing a fractional or huge negative number; passing an object whose `valueOf` returns a negative number or NaN (NaN |= 0 becomes 0, but a negative-returning valueOf triggers the throw); passing `undefined`-derived negative config values; passing a negative result of arithmetic (e.g. `maxSize - currentSize` when it goes negative).","commonSituations":"Config values read from env/JSON where a default of -1 is used as a sentinel; computing ID length from a subtraction that underflows; deserializing user input that contains a negative number; test code seeding lengths with negative placeholders; passing a string like '-21' that gets coerced to a negative number.","solutions":["Pass a non-negative integer to `random()`, e.g. `random(16)`.","Clamp the value before calling: `bytes = Math.max(0, Math.trunc(Number(bytes)))`.","Fix the upstream computation producing the negative value (e.g. guard subtraction results with Math.max(0, ...)).","If the value comes from user input/config, validate it is a positive integer before passing it on."],"exampleFix":"// before\nconst bytes = maxLen - currentLen\nconst buf = random(bytes) // throws if currentLen > maxLen\n// after\nconst bytes = Math.max(0, maxLen - currentLen)\nconst buf = random(bytes)","handlingStrategy":"validation","validationCode":"function isValidSize(n) {\n  return Number.isInteger(Number(n)) && Number(n) >= 0\n}\nif (!isValidSize(bytes)) bytes = Math.max(0, Math.trunc(Number(bytes))) || 0\nconst buffer = random(bytes)","typeGuard":"function isNonNegativeInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 0\n}","tryCatchPattern":"let buffer\ntry {\n  buffer = random(bytes)\n} catch (e) {\n  if (e instanceof RangeError && e.message === 'Wrong ID size') {\n    buffer = random(16) // sane default\n  } else {\n    throw e\n  }\n}","preventionTips":["Always pass literal positive integers to random().","Clamp computed sizes with Math.max(0, Math.trunc(x)).","Never pass objects with valueOf as sizes.","Validate config/env-provided sizes at startup."],"tags":["range-error","argument-validation","nanoid"],"backgroundTag":"invalid-id-size","analyzedSha":"07a39d62d84c21af5046fe6b2ef7b3e36ee557db","analyzedAt":"2026-08-30T01:36:55.444Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}