promise/no-callback-in-promise

Disallow calling a callback inside then() or catch()

If a callback throws while it runs inside then() or catch(), the error doesn't reach the caller. The promise turns it into a rejection. In the example below, if callback throws in the then(), the catch() calls it a second time with that error.

A callback is a function named callback, cb, done or next. Inside a function passed to then() or catch(), the rule reports calling one, and passing one as the first argument to another call. It also reports .then(callback) and .catch(callback).

A callback scheduled with setImmediate, setTimeout, requestAnimationFrame or nextTick runs after the promise handler has returned, so it isn't reported.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"promise/no-callback-in-promise" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"promise/no-callback-in-promise" = ["error", {
  exceptions = [], # list of strings
  timeoutsErr = false,
}]

Examples#

example.js2 problems
function getUser(id, callback) {
  fetchUser(id)
    .then(user => callback(null, user))
    .catch(callback);
}
example.js1 problem
fetchUser(id).then(user => finish(done, user));
example.jsNo problems
function getUser(id, callback) {
  fetchUser(id)
    .then(user => setImmediate(callback, null, user))
    .catch(err => setImmediate(() => callback(err)));
}

Options#

OptionDefaultWhat it does
exceptions[]Names from the list above that aren't callbacks in your code.
timeoutsErrfalseAlso report callbacks scheduled with setImmediate, setTimeout, requestAnimationFrame or nextTick.
example.jswith { "exceptions": ["next"] }No problems
app.get("/users/:id", (req, res, next) => {
  fetchUser(req.params.id)
    .then(user => res.json(user))
    .catch(next);
});
example.jswith { "timeoutsErr": true }1 problem
function getUser(id, callback) {
  fetchUser(id).then(user => setImmediate(callback, null, user));
}