Automattic/mongoose · error · TypeError
batchSize must be at least 1
Error message
batchSize must be at least 1
What it means
eachAsync rejects batchSize values below 1: 0 and negative numbers throw TypeError('batchSize must be at least 1'). batchSize of 0 usually means the developer intended no batching or driver default, but the server requires at least one document per batch, so Mongoose validates the lower bound eagerly.
Source
Thrown at lib/helpers/cursor/eachAsync.js:54
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;
for (let i = 0; i < parallel; ++i) {
enqueue(createFetch());View on GitHub (pinned to 49cdab0136)
Solutions
- Treat 0/negative as unset: const opts = n > 0 ? { batchSize: n } : {};.
- Or clamp: batchSize: Math.max(1, n).
- Fix the source producing non-positive values (env defaults, empty-length divisions).
Example fix
// before
const batchSize = Number(process.env.BATCH_SIZE ?? 0);
await cursor.eachAsync(fn, { batchSize }); // 0 -> TypeError
// after
const raw = Number(process.env.BATCH_SIZE ?? NaN);
const batchSize = Number.isInteger(raw) && raw >= 1 ? raw : undefined;
await cursor.eachAsync(fn, { batchSize }); // undefined = driver default Defensive patterns
Strategy: validation
Validate before calling
function toBatchSize(v) {
const n = v == null ? NaN : Number(v);
return Number.isInteger(n) && n >= 1 ? n : undefined; // undefined = driver default
}
await cursor.eachAsync(fn, { batchSize: toBatchSize(process.env.BATCH_SIZE) }); Type guard
function isValidBatchSize(v) {
return typeof v === 'number' && Number.isInteger(v) && v >= 1;
} Prevention
- Do not use 0 or -1 as 'use default' sentinels; use undefined/null and normalize.
- Validate env-driven numeric config at startup and clamp to minimums.
- Log the normalized batch size in ETL jobs so bad config is visible before cursors start.
When it happens
Trigger: cursor.eachAsync(fn, { batchSize: 0 }) intending unlimited; negative values from misconfigured env vars or arithmetic underflow; -1 sentinels copied from a different API's semantics.
Common situations: Env var defaulting to 0 when unset; computed batch sizes that reach 0 for empty inputs; conventions from other libraries where 0 means default.
Related errors
- batchSize must be a number
- batchSize must be an integer
- 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/96095913694bae8a.
Report an issue: GitHub.