Search code examples
node.jsexpresspromiseasync-awaitloopbackjs

Error: Callback was already called in loopback


I have the following code:

"use strict";
const Raven = require("raven");
Raven.config(
    "test"
).install();

module.exports = function(Reservation) {
  function dateValidator(err) {
    if (this.startDate >= this.endDate) {
      err();
    }
  }

  function sendEmail(campground) {
    return new Promise((resolve, reject) => {
      Reservation.app.models.Email.send(formEmailObject(campground), 
        function(
          err,
          mail
        ) {
           if (err) {
            console.log(err);
            Raven.captureException(err);
            reject(err);
           } else {
             console.log(mail);
             console.log("email sent!");
             resolve(mail);
           }
       });
   });
} 

  function formEmailObject(campground) {
    return {
      to: "loopbackintern@yopmail.com",
      from: "noreply@optis.be",
      subject: "Thank you for your reservation at " + campground.name,
      html:
        "<p>We confirm your reservation for <strong>" +
        campground.name +
        "</strong></p>"
    };
   }

Reservation.validate("startDate", dateValidator, {
 message: "endDate should be after startDate"
});

Reservation.observe("after save", async function(ctx, next) {
 try {
  const campground = await Reservation.app.models.Campground.findById(
    ctx.instance.campgroundId
  );
  const mail = await sendEmail(campground);
  next();
 } catch (e) {
  Raven.captureException(e);
  next(e);
 }
});
};

Sorry for the poor formatting. When the flow is done I get this error:

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

I am calling the next() callback in two places, one in the try code and one in the catch code. I assume that when it all goes right, next callback is called only once, and the same when it goes wrong. But it seems that it is called twice and I don't know why.

I also tried to call next outside the try/catch code but it results in the same error. If I left only the next that is called inside the catch code it doesn't throw the error.

Any idea? Thanks!


Solution

  • if you are using async function you shouldn't explicitly call next, it gets automatically called.

    check out this github issue for loopback async/await

    so your hook can be like the following.

     Reservation.observe("after save", async ctx => {
      try {
        const campground = await Reservation.app.models.Campground.findById(
          ctx.instance.campgroundId
        );
        const mail = await sendEmail(campground);
      } catch (e) {
        Raven.captureException(e);
        throw e;
      }
    });
    

    NB: you don't need to wrap it in try catch unless you want to modify/work with the error.