petkaantonov/bluebird · error · TypeError

The last argument to .catch() must be a function, got %s

Error message

The last argument to .catch() must be a function, got %s

What it means

`.catch()` (the overload taking multiple predicates) requires its LAST argument to be a handler function; the preceding arguments are predicate values/constructors matched against the rejection reason. Bluebird throws this TypeError when the final argument is anything else, because there would be no handler to invoke.

Source

Thrown at src/promise.js:131

Promise.prototype.caught = Promise.prototype["catch"] = function (fn) {
    var len = arguments.length;
    if (len > 1) {
        var catchInstances = new Array(len - 1),
            j = 0, i;
        for (i = 0; i < len - 1; ++i) {
            var item = arguments[i];
            if (util.isObject(item)) {
                catchInstances[j++] = item;
            } else {
                return apiRejection("Catch statement predicate: " +
                    OBJECT_ERROR + util.classString(item));
            }
        }
        catchInstances.length = j;
        fn = arguments[i];

        if (typeof fn !== "function") {
            throw new TypeError("The last argument to .catch() " +
                "must be a function, got " + util.toString(fn));
        }
        return this.then(undefined, catchFilter(catchInstances, fn, this));
    }
    return this.then(undefined, fn);
};

Promise.prototype.reflect = function () {
    return this._then(reflectHandler,
        reflectHandler, undefined, this, undefined);
};

Promise.prototype.then = function (didFulfill, didReject) {
    if (debug.warnings() && arguments.length > 0 &&
        typeof didFulfill !== "function" &&
        typeof didReject !== "function") {
        var msg = ".then() only accepts functions but was passed: " +
                util.classString(didFulfill);

View on GitHub (pinned to c220cfe480)

Solutions

  1. Ensure the last argument is a function: `promise.catch(TypeError, err => ...)`.
  2. If you only have one handler, call `.catch(fn)` with no predicates.
  3. Pass the function reference itself, not an invocation: `.catch(handleErr)` not `.catch(handleErr())`.

Example fix

// before
promise.catch(TypeError, err.message => console.log);
// after
promise.catch(TypeError, (err) => console.log(err.message));
Defensive patterns

Strategy: validation

Validate before calling

function safeCatch(p, ...args) {
  const last = args[args.length - 1];
  if (typeof last !== 'function') throw new TypeError('.catch() last argument must be a function');
  return p.catch(...args);
}

Type guard

const isHandler = (v) => typeof v === 'function';

Try / catch

try { p = p.catch(TypeError, handler); } catch (e) {
  if (String(e).includes('must be a function')) p = p.catch(defaultHandler);
  else throw e;
}

Prevention

When it happens

Trigger: `promise.catch(TypeError, 'oops')` (string as last arg); `promise.catch(predicate, someVar)` where someVar is undefined or not a function; mistyping `.catch(errHandler)` as `.catch(errHandler())` (passing the result of calling the handler).

Common situations: Mistakenly using Node-style `.catch(code, handler)` conventions in browser code; forgetting the handler after listing error predicates; passing an async IIFE result instead of the function itself.

Related errors


AI-assisted analysis of petkaantonov/bluebird@c220cfe480 (2026-09-02). Data as JSON: /api/errors/f237e9f3f46010a2. Report an issue: GitHub.