2

I am using express/node to create a back-end api for authentication/authorization and using mongodb to store the data.

I'm using express-validator to validate the input req. I want to validate whether a username already exists or not - the library recommends i should use an async function to do this.

Although it returns the data with the correct error message in postman, my server crashes with the message.

Error: Can't set headers after they are sent.

Server.js

app.use(validator({

    customValidators: {

        isUsernameAvailable: function(username) {
            return new Promise(function(resolve, reject) {

                User.findOne({'username': username}, function(err, results) { 

                    if(err) {
                        return resolve(err);
                    }
                    reject(results);

                });

            });
        }
    }

}));

auth.route.js

var express = require('express');
var router = express.Router();
var controller = require('../controllers/auth.controller');
var middleware = require('../middleware/auth.middleware');

router.post('/login', controller.login);
router.post('/register', middleware.register, controller.register);

module.exports = router;

auth.middleware.js

module.exports.register = function(req, res, next)
{
    req.checkBody({

        'username': {
            notEmpty: true,
            errorMessage: 'Username is required'
        },

        'email': {
            notEmpty: true,
            isEmail: {
                errorMessage: 'Invalid Email Address'
            },
            errorMessage: 'Email is required'
        },

        'password': {
            notEmpty: true,
            errorMessage: 'Password is required'
        },

        'password_confirmation': {
            notEmpty: true,
            errorMessage: 'Password Confirmation is required'
        }

    });

    req.assert('password_confirmation', 'Passwords do not match').equals(req.body.password);

    req.check('username', 'This username is already taken').isUsernameAvailable();


    var errors = req.validationErrors(true);

    if(errors) {

        return res.json({
            success: false,
            errors: errors
        });

    }

    req.asyncValidationErrors().catch(function(errors) {

        if(errors) {
            return res.json({
                success:false,
                errors: errors
            });
        };
    });


    next();

}
  • The error usually means that a callback has already been executed see: http://stackoverflow.com/questions/7042340/node-js-error-cant-set-headers-after-they-are-sent . Also try stepping through your code using node-debug. – AlwaysNull Jan 24 '16 at 15:39
  • Found answer here http://stackoverflow.com/a/42611431/7662526 – Ivan Borshchov Apr 07 '17 at 07:53

1 Answers1

1

I think it's because the following blocks are both run:

var errors = req.validationErrors(true);

    if(errors) {

        return res.json({
            success: false,
            errors: errors
        });

    }

    req.asyncValidationErrors().catch(function(errors) {

        if(errors) {
            return res.json({
                success:false,
                errors: errors
            });
        };
    });

The documentation says that you should use one or the other. req.validationErrors(true); is for synchronous, mapped errors whereas req.asyncValidationErrors() is for async un-mapped errors. At the minute, you are using both - both of them are getting run and trying to send a response (which is why you are getting the message: can't set headers after they are sent.

See the validation errors section on their readme for more information.

Ash
  • 6,483
  • 7
  • 29
  • 37