javascriptnode.jsexpresssequelize.js

Sequelize update query resulting in error


I'm running into an issue where querying my database for an update is returning an error in my express app using sequelize. I have the following code in my controller:

I'm seeing the following error in the console:

activateChecklist RESULTED IN AN ERROR:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I've tried adding async to the anonymous function being assigned to activateChecklist and await to Checklist.update but that did not change anything.

Is there a logical error in my code I am not seeing?

if I comment out the code from the line const id = req.params.id to just before the last closing bracket there error goes away.

exports.activateChecklist = (req, res, next) => {
    Checklist.update({ active: false }, { where: {} })
        .then(() => {
            console.log("All checklists set to inactive");
        })
        .catch((err) => {
            console.log("activateChecklist RESULTED IN AN ERROR: ".err);
        });
    //activate clicked on entry
    const id = req.params.id;
    Checklist.findByPk(id)
        .then((checklist) => {
            if (!checklist) {
                return res.status(404).send("Checklist not found");
            }
            return checklist.update({
                active: true,
            });
        })
        .then(() => {
            console.log("Checklist activated");
            res.redirect("/admin/all-checklists");
        })
        .catch((err) => {
            console.log("activateChecklist RESULTED IN AN ERROR: " + err);
            res.status(500).send("Error activating checklist");
        });
};

Solution

  • The issue you are having is that your code is attempting to respond to the request multiple times.

    Checklist.findByPk(id)
      .then((checklist) => {
        if (!checklist) {
          return res.status(404).send("Checklist not found"); // <— Responds to the request
        }
        return checklist.update({
          active: true,
        });
      })
      .then(() => {
        console.log("Checklist activated");
        res.redirect("/admin/all-checklists"); // <—- Also responds to the request, causing the error
      });
    

    Because that code is in a callback, and not the parent function, the return doesn't prevent the next chained .then from running. This means your program is attempting to both send a 404 response and a 302 (redirect) response, causing your error. See the below function for a simpler example of what's going on.

    async function myAsyncFunction() {
      return "result"
    }
    
    myAsyncFunction()
      .then((item) => {
        return console.log("Return A: ", item)
      })
      .then(() => {
        return console.log("Return B")
      })

    One way to resolve this is to make this a single .then() with an async callback, rather than promise chaining, as shown below

    Checklist.findByPk(id)
      .then(async (checklist) => {
        if (!checklist) {
          res.status(404).send("Checklist not found");
          return;
        }
        await checklist.update({
          active: true,
        });
        console.log("Checklist activated");
        res.redirect("/admin/all-checklists");
      })
      .catch((err) => {
        console.log("activateChecklist RESULTED IN AN ERROR: " + err);
        res.status(500).send("Error activating checklist");
      });