{"record":{"id":"7da93a50066e7637","repo":"Automattic/mongoose","slug":"batchsize-must-be-an-integer","errorCode":null,"errorMessage":"batchSize must be an integer","messagePattern":"batchSize must be an integer","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/helpers/cursor/eachAsync.js","lineNumber":52,"sourceCode":"  let aborted = false;\n\n  return new Promise((resolve, reject) => {\n    if (signal != null) {\n      if (signal.aborted) {\n        return resolve(null);\n      }\n\n      signal.addEventListener('abort', () => {\n        aborted = true;\n        return resolve(null);\n      }, { once: true });\n    }\n\n    if (batchSize != null) {\n      if (typeof batchSize !== 'number') {\n        throw new TypeError('batchSize must be a number');\n      } else if (!Number.isInteger(batchSize)) {\n        throw new TypeError('batchSize must be an integer');\n      } else if (batchSize < 1) {\n        throw new TypeError('batchSize must be at least 1');\n      }\n    }\n\n    iterate((err, res) => {\n      if (err != null) {\n        return reject(err);\n      }\n      resolve(res);\n    });\n  });\n\n  function iterate(finalCallback) {\n    let handleResultsInProgress = 0;\n    let currentDocumentIndex = 0;\n\n    let error = null;","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/helpers/cursor/eachAsync.js#L34-L70","documentation":"eachAsync requires batchSize to be an integer. Fractional values - commonly produced by arithmetic like total / 2 without rounding - throw TypeError('batchSize must be an integer') before any documents are fetched.","triggerScenarios":"cursor.eachAsync(fn, { batchSize: items.length / 2 }) yielding 2.5; dynamically computed adaptive batch sizes from averages or ratios; parseFloat('10.5') passed through.","commonSituations":"Dynamically sized batches in migration or backfill scripts; float math leaking into cursor options; unit conversions producing fractional values.","solutions":["Round explicitly: Math.max(1, Math.floor(computed)).","Clamp the rounded value to a sane range (e.g. 1..1000).","Omit batchSize when the computed value is not a positive integer."],"exampleFix":"// before\nconst batchSize = docs.length / workers; // 2.5\nawait cursor.eachAsync(fn, { batchSize }); // TypeError\n\n// after\nconst batchSize = Math.max(1, Math.floor(docs.length / workers));\nawait cursor.eachAsync(fn, { batchSize });","handlingStrategy":"validation","validationCode":"function toBatchSize(v) {\n  if (v == null) return undefined;\n  const n = typeof v === 'number' ? v : Number(v);\n  if (!Number.isInteger(n) || n < 1) {\n    throw new TypeError(`invalid batchSize: ${v}`);\n  }\n  return n;\n}\n// computed sizes are validated (throws) instead of leaking fractions into eachAsync\nconst batchSize = toBatchSize(docs.length / workers);","typeGuard":"function isValidBatchSize(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 1;\n}","tryCatchPattern":null,"preventionTips":["Round any computed batch size explicitly with Math.floor or Math.round.","Clamp computed sizes to a configured min/max (e.g. 1..1000).","Add unit tests for option-normalization helpers with fractional inputs."],"tags":["mongoose","cursor","eachasync","batch-size","integer"],"backgroundTag":"invalid-batch-size","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}