dubinc/dub · error
maxBatches must be greater than 0.
Error message
maxBatches must be greater than 0.
What it means
processInBatches validates its first argument and throws this Error immediately if maxBatches is not a positive number. maxBatches caps how many batch iterations will run, so a zero or negative value is meaningless and treated as a programmer error rather than a runtime condition.
Source
Thrown at packages/utils/src/functions/process-in-batches.ts:9
// Runs a batch operation up to `maxBatches` times in a single invocation.
// Use in cron jobs/background workers when you need to process a large set of rows without exceeding the function timeout.
// Each call to `processBatch` should itself be limited (e.g. Prisma `updateMany`/`deleteMany` with `limit`)
export async function processInBatches(
maxBatches: number,
processBatch: () => Promise<{ count: number }>,
): Promise<{ hasMore: boolean }> {
if (maxBatches <= 0) {
throw new Error("maxBatches must be greater than 0.");
}
for (let batch = 0; batch < maxBatches; batch++) {
const { count } = await processBatch();
if (count === 0) {
return {
hasMore: false,
};
}
}
// Exhausted allowed batches. There may still be work left.
return {
hasMore: true,
};
}
View on GitHub (pinned to f216b94a24)
Solutions
- Guard the call site: only invoke processInBatches when maxBatches > 0.
- Check where maxBatches is computed — Math.ceil(total/batchSize) is 0 when total is 0; skip the call entirely for empty datasets.
- Clamp the value: Math.max(1, computedBatches) if you always want at least one attempt.
- Validate the input with an assertion before the call for clearer stack traces.
Example fix
// before
const batches = Math.ceil(totalItems / BATCH_SIZE);
await processInBatches(batches, processBatch);
// after
const batches = Math.ceil(totalItems / BATCH_SIZE);
if (batches > 0) {
await processInBatches(batches, processBatch);
} Defensive patterns
Strategy: validation
Validate before calling
function assertPositive(n: number, name: string): void {
if (!Number.isInteger(n) || n <= 0) {
throw new RangeError(`${name} must be a positive integer, got ${n}`);
}
}
assertPositive(maxBatches, 'maxBatches');
await processInBatches(maxBatches, processBatch); Type guard
function isValidMaxBatches(n: unknown): n is number {
return typeof n === 'number' && Number.isInteger(n) && n > 0;
} Try / catch
try {
await processInBatches(maxBatches, processBatch);
} catch (e) {
if (e instanceof Error && e.message.includes('maxBatches must be greater than 0')) {
console.error(`Bad maxBatches value: ${maxBatches}`);
} else {
throw e;
}
} Prevention
- Skip the call entirely when the dataset is empty (totalItems === 0).
- Compute maxBatches with Math.max(1, Math.ceil(total / size)) if one attempt is always acceptable.
- Guard against NaN — NaN <= 0 is false, so it would slip past; validate Number.isFinite first.
- Unit-test batch-count computation with zero-item inputs.
When it happens
Trigger: Calling processInBatches(0, fn), processInBatches(-1, fn), or passing a variable computed to <= 0 (e.g. Math.ceil(total/size) where total is 0 or size exceeds total).
Common situations: Computing maxBatches from an empty dataset (total items = 0), passing an uninitialized/NaN variable that coerces into the check, or a config value defaulting to 0.
AI-assisted analysis of dubinc/dub@f216b94a24 (2026-08-31).
Data as JSON: /api/errors/840d0014e5e0cbb9.
Report an issue: GitHub.