Kim
Kim

Reputation: 1081

Node JS [Error: Can't set headers after they are sent.]

Hi lets say I have code like this:

router.get('/blablabla', function(req, res, next) {
    model
      .findOne({condition : req.body.condition})
      .then(function(data) {
        if(data) {
          return res.send("data already exists");
        }
        else {
          //DO CREATE THE NEW DATA

          return modelInstance.save();
        }
      })
      .then(function(data) {
        if(data) res.send("new data successfully saved");
      })
      .catch(function(err) {
        console.log(err);
      });
  });

In current condition if data already exists, there will be error

**[Error: Can't set headers after they are sent.]
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)**

Why this error raised? based on my knowledge after res.send() is being called then all the later code below it will not be executed right?

I am return data.save() because I want avoid nesting statement.

UPDATE ALTERNATIVE SOLUTION

router.get('/blablabla', function(req, res, next) {
    model
      .findOne({condition : req.body.condition})
      .then(function(data) {
        if(data) {
          return new Promise(function(resolve, reject) {
            return resolve();
          });
        }
        else {
           //DO CREATE THE NEW DATA

          return modelInstance.save();
        }
      })
      .then(function(data) {
        if(data) res.send("new data successfully saved");
        else res.send("data already exists");
      })
      .catch(function(err) {
        console.log(err);
      });
  });

Upvotes: 0

Views: 27

Answers (1)

jfriend00
jfriend00

Reputation: 707308

Your second .then() handler will still execute because the promise is not branched, it's chained so the chain keeps going and thus you will be doing two res.send() operations and that's what causes the error you see.

When you do:

return res.send("data already exists");

You are just returning a value from the .then() handler. Since that value is not a rejected promise, the promise stays resolved and the next .then() handler in the chain will execute.

You could do this:

router.get('/blablabla', function (req, res, next) {
    model.findOne({condition: req.body.condition}).then(function (data) {
        if (data) {
            return res.send("data already exists");
        } else {
            //DO mMODIFY THE DATA AND THEN SAVE THE DATA
            return data.save().then(function () {
                res.send("new data successfully saved");
            });
        }
    }).catch(function (err) {
        console.log(err);
    });
});

Or, you could do this (modification of your second try - assumes that data.save() returns a promise that resolves to a value):

router.get('/blablabla', function(req, res, next) {
    model
      .findOne({condition : req.body.condition})
      .then(function(data) {
        if (!data) {
          //DO mMODIFY THE DATA AND THEN SAVE THE DATA
          return data.save();
        }
        return data;
      })
      .then(function(data) {
        if(data) res.send("new data successfully saved");
        else res.send("data already exists");
      })
      .catch(function(err) {
        console.log(err);
      });
  });

Upvotes: 1

Related Questions