souvikc
souvikc

Reputation: 1031

Node/Express: Cannot set headers after they are sent to the client

I have the below code where I am trying to validate a user with its credentials from Mongo DB :

{
  validate: async function (email, password, res) {
    console.log('Inside validate method');

    try {
      var dbUserObj = await User.findOne({ email: email }, (err, user) => {

        console.log('Inside validate method111111');

        if (err) {
          return res.status(500).send('Error on the server.');
        }

        console.log('Inside validate method 22222');

        if (!user) {
          return res.status(404).send('No user found.');
        }

        console.log('Inside validate method33333');

        var passwordIsValid = bcrypt.compareSync(password, user.password);

        console.log('Is Valid Password :: ' + passwordIsValid);

        if (!passwordIsValid) {
          return res.status(401).send({
            auth: false,
            token: null
          });
        }
      });
    } catch (e) {

    }

    console.log('DDDDBBBB USSSERRRR :::' + dbUserObj);
    return dbUserObj;
  }
}

The below code calls the validate method :

var auth = {

login: function(req, res,next) {

 console.log('Inside login');
var email = req.body.email || '';
var password=req.body.password || '';
console.log('Before validate user');
// Fire a query to your DB and check if the credentials are valid
var dbUserObj = auth.validate(email,password,res);

if (!dbUserObj) { // If authentication fails, we send a 401 back
  res.status(401);
  res.json({
    "status": 401,
    "message": "Invalid credentials"
  });
  return;
}

if (dbUserObj) {      
  res.send(genToken(dbUserObj));

}

}

Whenever there is a condition when the password is incorrect i am getting the error :

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Cannot really figure out the issue.

Upvotes: 0

Views: 6338

Answers (1)

Patrick Roberts
Patrick Roberts

Reputation: 51846

The route that calls your validate() needs to accept the next callback parameter from express, otherwise the framework assumes that when the asynchronous function returns (which occurs at the first await expression), it has completed all its work and at that point it continues down its routes to the default error handling which sends a 404 before your database query resumes async control flow in validate.

When your route handler accepts the next parameter, it indicates to express that the route will handle asynchronously, and you can do 1 of 3 things:

  1. Don't call next() if you already send a response (which you always do in this case).
  2. Call next() with no arguments if you don't send a response and want to delegate the response handling to the remaining routes.
  3. Call next(error) if you want to delegate the response handling to remaining middleware which will handle the error reporting and response for you.

Upvotes: 2

Related Questions