javascriptnode.jsexpresspassport.js

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


app.post("/login", async (req, res) => {
    // Destructure Req Body
    const { email, password } = req.body;

    // Validate Body
    if (!email || !password) {
        res.status(400).json({ success: false, message: "PARAMS_MISSING" });
        
    }

    // Build the SQL query
    const query = `SELECT * FROM user WHERE email = "${email}"`;

    // Get the user from DB
    const user = await db(query);

    // Check if password is valid
    const isPasswordValid =  decryptPassword(user.hash_password, password);

    // Return if password is not valid
    if (!isPasswordValid) {
        res.status(401).json({ success: false, message: "INAVLID_PASSWORD" });

    }
       
    
    // Generate Token
    const token = generateToken({ id: user.id, email: user.email });

    // Save Cookie
    res.cookie("token", token, { maxAge: 900000, httpOnly: true });
     res.end();
    // Return
    res.json({ success: true, message: "USER_AUTHENTICATED" });
});

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

I m getting this error again and again. I'm facing this weird issue in NodeJS when using it with Passport.js, Express. Basically, I keep getting the error saying "Cannot set headers after they are sent to the client", even though I'm not sending more than one header.


Solution

  • This error means the 'res' object respond twice. E.g: in your '// Validate body' if the password or email are missing your http connection respond 'res.status().json().'(note that is closing the http connection), but as you didn't stop the execution of the code, it carries on then it may respond a second time in the // Return if password is not valid which create the err as the header can not be set twice and the connection is already close.

    Than more here you error is Unhandled, as an Async function reject, the error must be handle, wrapping the code in a try{} catch(e){} will fix it.

    So that should fix your issues

    app.post("/login", async (req, res) => {
        try{
        // Destructure Req Body
        const { email, password } = req.body;
    
        // Validate Body
        if (!email || !password) {
            res.status(400).json({ success: false, message: "PARAMS_MISSING" });
            return // stop execution of the function
            
        }
    
        // Build the SQL query
        const query = `SELECT * FROM user WHERE email = "${email}"`;
    
        // Get the user from DB
        const user = await db(query);
    
        // Check if password is valid
        const isPasswordValid =  decryptPassword(user.hash_password, password);
    
        // Return if password is not valid
        if (!isPasswordValid) {
            res.status(401).json({ success: false, message: "INAVLID_PASSWORD" });
            return // stop exec of the function
    
        }
           
        
        // Generate Token
        const token = generateToken({ id: user.id, email: user.email });
    
        // Save Cookie
        res.cookie("token", token, { maxAge: 900000, httpOnly: true });
         res.end();
        // Return
        res.json({ success: true, message: "USER_AUTHENTICATED" });
        } catch(err) {
            console.error(err) // code to handle the err
        }
    });
    

    But still, a problem remain as at the end of your script, you have a res.end()(which terminate the connection) and right after a res.json() which will fail as the connection has been close the line before (than more the statusCode is missing)