caolan/async · error · RangeError

concurrency limit cannot be less than 1

Error message

concurrency limit cannot be less than 1

What it means

The shared worker underlying eachOfLimit/eachLimit/mapLimit etc. validates the concurrency argument. A limit of 0 or negative would mean no worker can ever run, so a RangeError is thrown immediately. The limit must be a positive integer.

Source

Thrown at lib/internal/eachOfLimit.js:12

import once from './once.js'
import iterator from './iterator.js'
import onlyOnce from './onlyOnce.js'
import {isAsyncGenerator, isAsyncIterable} from './wrapAsync.js'
import asyncEachOfLimit from './asyncEachOfLimit.js'
import breakLoop from './breakLoop.js'

export default (limit) => {
    return (obj, iteratee, callback) => {
        callback = once(callback);
        if (limit <= 0) {
            throw new RangeError('concurrency limit cannot be less than 1')
        }
        if (!obj) {
            return callback(null);
        }
        if (isAsyncGenerator(obj)) {
            return asyncEachOfLimit(obj, limit, iteratee, callback)
        }
        if (isAsyncIterable(obj)) {
            return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback)
        }
        var nextElem = iterator(obj);
        var done = false;
        var canceled = false;
        var running = 0;
        var looping = false;

        function iterateeCallback(err, value) {
            if (canceled) return

View on GitHub (pinned to 13dfaf13f3)

Solutions

  1. Pass a positive integer, e.g. Math.max(1, configuredLimit)
  2. For unlimited concurrency use async.each/async.map instead of the Limit variants
  3. Validate/normalize config before calling: limit = Number(cfg) > 0 ? Number(cfg) : 1
  4. Fix the computation producing 0 or NaN

Example fix

// before
await async.mapLimit(items, config.concurrency, mapper);
// after
const limit = Math.max(1, parseInt(config.concurrency, 10) || 1);
await async.mapLimit(items, limit, mapper);
Defensive patterns

Strategy: validation

Validate before calling

const assertLimit = (n) => { const v = Number(n); if (!Number.isInteger(v) || v < 1) throw new RangeError('concurrency limit cannot be less than 1'); return v; };

Type guard

function isValidLimit(n) {
  return Number.isInteger(n) && n >= 1;
}

Try / catch

try {
  await async.mapLimit(items, limit, mapper);
} catch (err) {
  if (err instanceof RangeError) {
    return async.map(items, mapper); // unlimited fallback
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling async.eachLimit(coll, 0, iteratee), async.mapLimit(coll, -1, fn), or passing a computed concurrency value that evaluates to 0 (e.g. Math.ceil(list.length / 0), an unset config variable defaulting to 0).

Common situations: Config value like CONCURRENCY=0 from environment, division producing 0/NaN, off-by-one when computing parallelism from CPU count, copying examples and setting limit 0 to mean 'unlimited' (it does not — use each/map instead).

Related errors


AI-assisted analysis of caolan/async@13dfaf13f3 (2026-08-28). Data as JSON: /api/errors/72846680c8730abc. Report an issue: GitHub.