{"record":{"id":"a6ba06795c2288f5","repo":"trekhleb/javascript-algorithms","slug":"items-must-not-be-empty","errorCode":null,"errorMessage":"Items must not be empty","messagePattern":"Items must not be empty","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/algorithms/statistics/weighted-random/weightedRandom.js","lineNumber":22,"sourceCode":" *\n * For example:\n * - items = ['banana', 'orange', 'apple']\n * - weights = [0, 0.2, 0.8]\n * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return\n * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)\n *\n * @param {any[]} items\n * @param {number[]} weights\n * @returns {{item: any, index: number}}\n */\n/* eslint-disable consistent-return */\nexport default function weightedRandom(items, weights) {\n  if (items.length !== weights.length) {\n    throw new Error('Items and weights must be of the same size');\n  }\n\n  if (!items.length) {\n    throw new Error('Items must not be empty');\n  }\n\n  // Preparing the cumulative weights array.\n  // For example:\n  // - weights = [1, 4, 3]\n  // - cumulativeWeights = [1, 5, 8]\n  const cumulativeWeights = [];\n  for (let i = 0; i < weights.length; i += 1) {\n    cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);\n  }\n\n  // Getting the random number in a range of [0...sum(weights)]\n  // For example:\n  // - weights = [1, 4, 3]\n  // - maxCumulativeWeight = 8\n  // - range for the random number is [0...8]\n  const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];\n  const randomNumber = maxCumulativeWeight * Math.random();","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/statistics/weighted-random/weightedRandom.js#L4-L40","documentation":"The second guard inside weightedRandom(): after item/weight lengths are proven equal, an empty items array is rejected because there is nothing to sample. Because the size check runs first, weightedRandom([], []) produces this message, not the size error. The function must return an {item, index} pair, which is impossible with zero candidates, so it fails fast.","triggerScenarios":"weightedRandom([], []); a prize/loot/name table that loaded empty because a filter removed everything, the config list is empty, or the database query returned no rows before the first draw.","commonSituations":"Empty configuration at first startup, over-matching filters, feature flags disabling all options, and placeholder empty arrays left in test fixtures.","solutions":["Check the source of the list - it is empty at call time; log its length and the filter that produced it","Guard the call site: if (items.length === 0) return a sensible default instead of sampling","Fix the loader/config so the list is populated before the first draw"],"exampleFix":"// before\nimport weightedRandom from './src/algorithms/statistics/weighted-random/weightedRandom';\nconst pick = weightedRandom(prizes, prizeWeights);\n// prizes and prizeWeights both [] -> throws\n\n// after\nif (prizes.length === 0) {\n  return null; // no prizes configured\n}\nconst pick = weightedRandom(prizes, prizeWeights);","handlingStrategy":"validation","validationCode":"if (!Array.isArray(items) || items.length === 0) {\n  return null; // nothing to sample\n}\nweightedRandom(items, weights);","typeGuard":"const isNonEmptyArray = (a) => Array.isArray(a) && a.length > 0;","tryCatchPattern":"try {\n  pick = weightedRandom(items, weights);\n} catch (e) {\n  if (e.message === 'Items must not be empty') {\n    pick = null; // empty pool\n  } else {\n    throw e;\n  }\n}","preventionTips":["Treat an empty candidate pool as an explicit state at the call site","Validate config-loaded lists once at startup, not per draw","Equal-length empties land here, not on the size error - test both"],"tags":["statistics","random-sampling","empty-array","validation"],"backgroundTag":"empty-array-argument","analyzedSha":"85293e3e2b88f4d2ce330d956b139cf628aa1e82","analyzedAt":"2026-08-24T05:59:10.417Z","schemaVersion":2},"datasetVersion":"2026-08-24T07:17:09.176Z"}