0

When I uncomment this line: return done(null, false, { message: 'Incorrect username' }); in the following code, Node.js runs without any error, otherwise, Node.js gives an error mentioned later:

//we need to define a local Strategy to authenticate with username and password
passport.use(new LocalStrategy(
    function(username, password, done) { //start of custom code
        //from here starts our custom code (inside this function scope)
        //outside this scope is from passport API documentation
        //process.nextTick(function() {
        UserFind(username, function(err, user) {
                if (err) {
                    return done(err);
                } else if (!user || user.length == 0) {
                    //When I uncomment the following line of code, an error occurs, but when I comment out the following, no error is received:
                    //return done(null, false, { message: 'Incorrect username' });
                } else {
                    console.log('user._id:' + user._id);
                    console.log('typeof user: ' + typeof(user));
                    console.log('user.username: ' + user.username);
                    console.log('user.password: ' + user.password);
                    if (password !== user.password) {
                        return done(null, false, { message: 'Incorrect password' });
                    }
                    return done(null, user);
                }

            })
            //}) //process.nextTick
    } //end of custom code
));

The error received when I uncomment the above-mentioned line:

_http_outgoing.js:359 throw new Error('Can\'t set headers after they are sent.'); ^

Error: Can't set headers after they are sent. at ServerResponse.setHeader (_http_outgoing.js:359:11) at ServerResponse.header (/home/ict/Documents/hookahDB/serverjs/node_modules/express/lib/response.js:719:10) at ServerResponse.location (/home/ict/Documents/hookahDB/serverjs/node_modules/express/lib/response.js:836:15) at ServerResponse.redirect (/home/ict/Documents/hookahDB/serverjs/node_modules/express/lib/response.js:874:18) at allFailed (/home/ict/Documents/hookahDB/serverjs/node_modules/passport/lib/middleware/authenticate.js:132:20) at attempt (/home/ict/Documents/hookahDB/serverjs/node_modules/passport/lib/middleware/authenticate.js:167:28) at Strategy.strategy.fail (/home/ict/Documents/hookahDB/serverjs/node_modules/passport/lib/middleware/authenticate.js:284:9) at verified (/home/ict/Documents/hookahDB/serverjs/node_modules/passport-local/lib/strategy.js:82:30) at /home/ict/Documents/hookahDB/serverjs/index.js:158:28 at /home/ict/Documents/hookahDB/serverjs/index.js:144:16

I wonder why that single line is cause of the error and how I can resolve it. Thanks.

EDIT

Callback function is shown below:

function UserFind(username, cb) {
    db.view('users/by_username', function(err, res) {
        if (err) {
            //db.view returned error
            return cb(err);
        }
        res.forEach(function(key, value, id) {
                //1st input=key|username, 2nd input=value|userDocument, 3rd input=id|_id
                //console.log('key: '+key+' row: '+row+' id: '+ id);
                if (username === key) {
                    //found the user
                    return cb(false, value);
                }
            })
            //couldn't find the user by forEach loop
        return cb(false, false);
    })
}
Megidd
  • 7,089
  • 6
  • 65
  • 142

1 Answers1

1

That error message is caused by a timing error in the handling of an async response that causes you to attempt to send data on a response after the response has already been sent.

It usually happens when people treat an async response inside an express route as a synchronous response and they end up sending data twice.

You should add else in your statement

if (password !== user.password) {
   return done(null, false, { message: 'Incorrect password' });
} else {
    return done(null, user);
}

Update:

function UserFind(username, cb) {
    var userFound = false, userVal = "";
    db.view('users/by_username', function(err, res) {
        if (err) {
            //db.view returned error
            return cb(err);
        }
        res.forEach(function(key, value, id) {
                //1st input=key|username, 2nd input=value|userDocument, 3rd input=id|_id
                //console.log('key: '+key+' row: '+row+' id: '+ id);
                if (username === key) {
                    //found the user
                    userFound = true;
                    userVal = value;
                }
            });

       if (userFound) {
          return cb(false, userVal);
       } else {
         // User did not found
         return cb(false, false);
       }
    })
}
Megidd
  • 7,089
  • 6
  • 65
  • 142
digit
  • 4,479
  • 3
  • 24
  • 43
  • I added `else` but the error is received, I'm not sure why – Megidd Jan 01 '17 at 06:58
  • 1
    It must be somewhere else that you return response twice. Can you show done callback function here? – digit Jan 01 '17 at 07:03
  • `done` callback is from passport.js package, I showed the `UserFind` function. – Megidd Jan 01 '17 at 07:09
  • I feel like the error is figured out now: when a user is found by `UserFind`, I expected the `!user` to be `false`, however to my surprise, even when a user is found by `UserFind` the returned `!user` is `true` – Megidd Jan 01 '17 at 07:12
  • 1
    You shouldn't return callback in the loop as when it found the value multiple, the callback will return multiple. Please see my latest answer and implement it in you code. Thanks – digit Jan 01 '17 at 07:16