{"record":{"id":"f7d5b4209db5b866","repo":"caolan/async","slug":"expected-a-function","errorCode":null,"errorMessage":"expected a function","messagePattern":"expected a function","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/internal/wrapAsync.js","lineNumber":16,"sourceCode":"import asyncify from '../asyncify.js'\n\nfunction isAsync(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncFunction';\n}\n\nfunction isAsyncGenerator(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncGenerator';\n}\n\nfunction isAsyncIterable(obj) {\n    return typeof obj[Symbol.asyncIterator] === 'function';\n}\n\nfunction wrapAsync(asyncFn) {\n    if (typeof asyncFn !== 'function') throw new Error('expected a function')\n    return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;\n}\n\nexport default wrapAsync;\n\nexport { isAsync, isAsyncGenerator, isAsyncIterable };\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/caolan/async/blob/13dfaf13f3fc809ba1c9c39d5e267ac6959cbf4a/lib/internal/wrapAsync.js#L1-L23","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the argument is a function before calling: console.log(typeof fn)","Fix the import — ensure the helper is exported and imported by the right name","Pass the function reference, not its invocation result","Bind detached methods: obj.method.bind(obj)"],"exampleFix":"// before\nawait async.each(keys, processKey(), cb); // invoked\n// after\nawait async.each(keys, processKey, cb);","handlingStrategy":"type-guard","validationCode":"if (typeof iteratee !== 'function') throw new TypeError('iteratee must be a function');","typeGuard":"function isCallable(v) {\n  return typeof v === 'function';\n}","tryCatchPattern":"try {\n  await async.each(coll, iteratee);\n} catch (err) {\n  if (String(err.message) === 'expected a function') {\n    console.error('Check the iteratee/task import and reference');\n  } else throw err;\n}","preventionTips":["Pass function references, not invocation results","Verify imports exist at call time (watch for circular-import undefined)","typeof-check dynamically supplied task functions before handing them to async"],"tags":["async","type-error","validation"],"backgroundTag":"expected-function","analyzedSha":"13dfaf13f3fc809ba1c9c39d5e267ac6959cbf4a","analyzedAt":"2026-08-28T22:50:46.507Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}