Search code examples
node.jsasync-awaitloopbackjses6-promise

UnhandledPromiseRejectionWarning: Callback was already called (Loopback remote method)


I'm getting an error that says

(node:27301) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.

From what I understand about rejecting promises in await's and per the Mozilla description:

If the Promise is rejected, the await expression throws the rejected value.

I reject the error in the callback that's wrapped around my Promise like so:

Airport.nearbyAirports = async (location, cb) => {
  let airports
  try {
    airports = await new Promise((resolve, reject) => {
      Airport.find({
        // code
      }, (err, results) => {
        if (err)
          reject(err) // Reject here
        else
          resolve(results)
      })
    })
  } catch (err) { // Catch here
    cb(err, null)
    return
  }
  if (!airports.empty)
    cb(null, airports)
  }

My question is

  1. Why does it still consider my promise rejection unhandled? I thought the catch statement should silent this error.
  2. Why does it consider my callback already called? I have a return statement in my catch, so both should never be called.

Solution

  • The problem was actually my framework (LoopbackJS), not my function. Apparently at the time of writing this, using promises are not supported:

    https://loopback.io/doc/en/lb3/Using-promises.html#setup

    Meaning I can't even use await in my function because the remote method wraps my function somewhere else, so async would always be unhandled. I ended up going back to a Promise-based implementation of the inner code:

    Airport.nearbyAirports = (location, cb) => {
    const settings = Airport.dataSource.settings
    const db = DB(settings)
    let airports
    NAME_OF_QUERY().then((res) => {
      cb(null, res)
    }).catch((err) => {
      cb(err, null)
    })