Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.
like image 691
Huy-Anh Hoang Avatar asked Dec 18 '22 02:12

Huy-Anh Hoang


2 Answers

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)
})
like image 60
Huy-Anh Hoang Avatar answered Dec 20 '22 17:12

Huy-Anh Hoang


If Airport.find() throws an exception, then execution will jump to your catch block and your Promise will never be resolved or rejected. Perhaps you need to wrap it in its own try/catch:

Airport.nearbyAirports = async (location, cb) => {
  let airports
  try {
    airports = await new Promise((resolve, reject) => {
      try {
        Airport.find({
          // code
        }, (err, results) => {
          if (err)
            reject(err) // Reject here
          else
            resolve(results)
        })
      } catch (err) {
        reject(err) // Reject here too
        cb(err, null)
      }
    })
  } catch (err) { // Catch here
    cb(err, null)
    return
  }
  if (!airports.empty)
    cb(null, airports)
  }
like image 26
Rob Johansen Avatar answered Dec 20 '22 18:12

Rob Johansen