Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Why am I getting the error: "Can't set headers after they are sent." - in my node application?

I have a pretty basic node application, which I'm using to create a REST API. I'm getting a very strange error when I try to make a post request to the API: http://localhost:5000/login

ERROR: "Can't set headers after they are sent"

I have broken it up in to the three files that are required to set up the API: 1) The server file that listens on the port 2) The route file 3) The controller file, that handles the req, res 4) AppError - my custom class that handles errors

without else clause - (gets error):

What is happening- if the password and email are empty, then it should throw an error, and end the program, alongside send the appropriate error message. However, what is actually happening is, that I'm getting the "success". So it's skipping the conditional. Why is that?

exports.login = (req, res, next) => {
    const {email, password} = req.body;

//if password and email are empty, then create an error

    if(!email || !password) {
        next(new AppError('Please provide email and password', 400));
    } 
    const token = 'login successful';

        res.status(201).json({
            status: 'success',
            token: token
        });
};

with else clause - (no error)

This version works, as I use the "else" clause

exports.login = (req, res, next) => {
    const {email, password} = req.body;

    if(!email || !password) {
        next(new AppError('Please provide email and password', 400));
    } else {

        const token = 'login successful';

        res.status(201).json({
            status: 'success',
            token: token
        });

    } 
};

SERVER.JS FILE:

// import routes

const productsRoute = require('./routes/products');
const userRoute = require('./routes/userRoute');

app.use('/products', productsRoute);
app.use('/', userRoute);

// will catch all urls that arent recognised
app.all('*', (req, res, next) => {
    next(new AppError(`Can't find ${req.originalUrl} on the server!`, 404));
});


// global error handler:  express will know that if there are 4 params, that it is an error middleware
app.use(globalErrorHandler);

const PORT = 5000;

app.listen(PORT, () => console.log(`server started on port ${PORT}`));

ROUTE FILE: (userRoute)

const express = require('express');
const router = express.Router();
const authControllers = require('../controllers/authController');

router.post('/signup', authControllers.signup);
router.post('/login', authControllers.login);

module.exports = router;

CONTROLLER FILE:

exports.login = (req, res, next) => {
    const {email, password} = req.body;

    if(!email || !password) {
        next(new AppError('Please provide email and password', 400));
    } 
    const token = 'login successful';

        res.status(201).json({
            status: 'success',
            token: token
        });
};

APP ERROR FILE

class AppError extends Error {
    constructor(message, statusCode) {
        super(message);
        this.statusCode = statusCode;
        this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
        this.isOperational = true;

        Error.captureStackTrace(this, this.constructor)
    }
}

module.exports = AppError;

1 Answer

I figured it out - I just needed to include a return before the next() function

   if(!email || !password) {
        return next(new AppError('Please provide email and password', 400));
    }