caolan/async · error · Error

expected a function

Error message

expected a function

What it means

wrapAsync normalizes a task/iteratee argument that may be callback-style, an async function, or a promise-returning function. If the value passed where a function is expected is not callable at all, it throws 'expected a function' immediately. This is the entry-point validation for nearly every async.js control-flow helper.

Source

Thrown at lib/internal/wrapAsync.js:16

import asyncify from '../asyncify.js'

function isAsync(fn) {
    return fn[Symbol.toStringTag] === 'AsyncFunction';
}

function isAsyncGenerator(fn) {
    return fn[Symbol.toStringTag] === 'AsyncGenerator';
}

function isAsyncIterable(obj) {
    return typeof obj[Symbol.asyncIterator] === 'function';
}

function wrapAsync(asyncFn) {
    if (typeof asyncFn !== 'function') throw new Error('expected a function')
    return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;
}

export default wrapAsync;

export { isAsync, isAsyncGenerator, isAsyncIterable };

View on GitHub (pinned to 13dfaf13f3)

Solutions

  1. Verify the argument is a function before calling: console.log(typeof fn)
  2. Fix the import — ensure the helper is exported and imported by the right name
  3. Pass the function reference, not its invocation result
  4. Bind detached methods: obj.method.bind(obj)

Example fix

// before
await async.each(keys, processKey(), cb); // invoked
// after
await async.each(keys, processKey, cb);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof iteratee !== 'function') throw new TypeError('iteratee must be a function');

Type guard

function isCallable(v) {
  return typeof v === 'function';
}

Try / catch

try {
  await async.each(coll, iteratee);
} catch (err) {
  if (String(err.message) === 'expected a function') {
    console.error('Check the iteratee/task import and reference');
  } else throw err;
}

Prevention

When it happens

Trigger: async.map(coll, undefined, cb), passing a method that was detached from its object and is undefined, passing a promise or result object instead of the function, a typo'd import (async.waterfall(coll, notImported)), passing null as the iteratee.

Common situations: Bad imports/circular imports leaving the function undefined at call time, destructuring a module property that doesn't exist, passing an already-invoked function's result instead of the function itself (fn() vs fn), minified code misreferencing symbols.

Related errors


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