Search code examples
mongodbexpressmongoosemongoose-schema

I am getting this error : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client


When I am sending POST Request for Login, then show this Error. I have used mongoose & MongoDB Atlas.

If I send POST request with valid email & password, it also shows this error.

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

But POST request for registration is working well.

User Model

const mongoose = require('mongoose')
const Schema = mongoose.Schema

const userSchema = new Schema({
    name: {
        type: String,
        required: true,
        trim: true
    },
    email: {
        type: String,
        required: true,
    },
    password: {
        type: String,
        required: true
    }, 
    balance: Number,
    income: Number,
    expense: Number,
    transactions: {
        type: [{
            type: Schema.Types.ObjectId,
            ref: 'Transaction'
        }]
    }
})

const User = mongoose.model('User', userSchema)
module.exports = User

User Controller

const registorValidate = require('../validator/registrationValidate')
const User = require('../models/userModel')
const bcrypt = require('bcrypt')
const loginValidate = require('../validator/loginValidator')
const jwt = require('jsonwebtoken')

module.exports = {
    login: (req, res) => {
        const { email, password } = req.body
        let logValidate = loginValidate({ email, password })

        if (!logValidate.isValid) {
            res.status(400).json(logValidate.error)
            return
        }

        User.findOne({ email })
            .then(user => {
                if (!user) {
                    console.log(`${email} not found`)
                    res.json({
                        msg: `${email} not found`
                    })
                }
                bcrypt.compare(password, user.password, (err, result) => {
                    if (err) {
                        res.status(400).json({
                            msg: 'Error occured'
                        })
                    }
                    if (!result) {
                        res.status(404).json({
                            msg: `Password doesn't match`
                        })
                    }
                    let token = jwt.sign({
                        _id: user._id,
                        name: user.name,
                        email: user.email
                    }, 'SECRET', { expiresIn: '2h' })

                    res.status(200).json({
                        msg: 'Login successful',
                        token: `Bearer ${token}`
                    })

                })
                return
            })
            .catch(err => {
                res.status(500).json({
                    msg: 'Error occured'
                })
            })

        res.end()

    },
    registration: (req, res) => {
        let { name, email, password, confirmPassword } = req.body
        let validate = registorValidate({ name, email, password, confirmPassword })

        if (!validate.isValid) {
            res.status(400).json(validate.error)
        } else {
            User.findOne({ email })
                .then(user => {
                    if (user) {
                        res.json({
                            msg: `${email} is already exist`
                        })
                    } else {
                        bcrypt.hash(password, 11, (err, hash) => {
                            if (err) {
                                res.status(500).json({
                                    msg: 'Server error occured'
                                })
                            }
                            let user = new User({
                                name,
                                email,
                                password: hash
                            })
                            user.save()
                                .then(user => {
                                    res.status(201).json({
                                        msg: `Thanks ${name} for your registration`,
                                        user
                                    })
                                })
                                .catch(err => {
                                    res.status(500).json({
                                        msg: 'Error occured'
                                    })
                                })
                        })
                    }
                })
                .catch(err => {
                    res.status(500).json({
                        msg: 'Error occured'
                    })
                })
        }
    }
}

Login Validator

const validator = require('validator')

const validate = user => {
    let error = {}

    // Email validator
    if (!user.email) {
        error.email = 'Please provide an Email'
    } else if (!validator.isEmail(user.email)) {
        error.email = 'Please provide a valid Email'
    }

    // Password validate
    if (!user.password) {
        error.password = 'Please provide a password'
    } else if (user.password.length < 6) {
        error.password = 'Password Must be greater or Equal to 6 characters'
    }

    return {
        error,
        isValid: Object.keys(error).length === 0
    }
}

module.exports = validate

Thanks.


Solution

  • You don't need to put res.end() because when you called res.json() earlier, it already sent the response.

    Please be advised that you should return when you call res.end(), res.send(), 'res.json()' and other operations that send the response, just like what you did with res.status(400).json(logValidate.error)

    This should be one of the ways prevent you from getting ERR_HTTP_HEADERS_SENT, but keep in mind that if you have nested callbacks, you should return from the outer scope as well