Automattic/mongoose · error · TypeError
batchSize must be an integer
Error message
batchSize must be an integer
What it means
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.
Source
Thrown at lib/helpers/cursor/eachAsync.js:52
let aborted = false;
return new Promise((resolve, reject) => {
if (signal != null) {
if (signal.aborted) {
return resolve(null);
}
signal.addEventListener('abort', () => {
aborted = true;
return resolve(null);
}, { once: true });
}
if (batchSize != null) {
if (typeof batchSize !== 'number') {
throw new TypeError('batchSize must be a number');
} else if (!Number.isInteger(batchSize)) {
throw new TypeError('batchSize must be an integer');
} else if (batchSize < 1) {
throw new TypeError('batchSize must be at least 1');
}
}
iterate((err, res) => {
if (err != null) {
return reject(err);
}
resolve(res);
});
});
function iterate(finalCallback) {
let handleResultsInProgress = 0;
let currentDocumentIndex = 0;
let error = null;View on GitHub (pinned to 49cdab0136)
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.
Example fix
// before
const batchSize = docs.length / workers; // 2.5
await cursor.eachAsync(fn, { batchSize }); // TypeError
// after
const batchSize = Math.max(1, Math.floor(docs.length / workers));
await cursor.eachAsync(fn, { batchSize }); Defensive patterns
Strategy: validation
Validate before calling
function toBatchSize(v) {
if (v == null) return undefined;
const n = typeof v === 'number' ? v : Number(v);
if (!Number.isInteger(n) || n < 1) {
throw new TypeError(`invalid batchSize: ${v}`);
}
return n;
}
// computed sizes are validated (throws) instead of leaking fractions into eachAsync
const batchSize = toBatchSize(docs.length / workers); Type guard
function isValidBatchSize(v) {
return typeof v === 'number' && Number.isInteger(v) && v >= 1;
} Prevention
- 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.
When it happens
Trigger: cursor.eachAsync(fn, { batchSize: items.length / 2 }) yielding 2.5; dynamically computed adaptive batch sizes from averages or ratios; parseFloat('10.5') passed through.
Common situations: Dynamically sized batches in migration or backfill scripts; float math leaking into cursor options; unit conversions producing fractional values.
Related errors
- batchSize must be a number
- batchSize must be at least 1
- Mongoose does not support using async iterators with an exis
- Arguments must be aggregate pipeline operators
- Invalid addFields() argument. Must be an object
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/7da93a50066e7637.
Report an issue: GitHub.