Search code examples
javascriptnode.jsexpresscustom-error-handling

Error cannot set headers after they are set to client


Im creating and employee leave managment system. Everything works fine until when I try to update the leave status by admin and th logged in acc or user is not roled as admin.

Ive a middleware that checks the authentication of user and role of user when an employeee tries to access this route it crashes the server logging cannot set headers already set to client and then ive to restart the server and access the route again

here is my Auth code:

const jwt = require("jsonwebtoken");
const employeeModels = require("../models/employeeModels");

exports.isAuthenticated = async (req, res, next) => {
    try {
        const { token } = req.cookies;
        if (!token)
            return res
                .status(400)
                .json({ success: false, error: "Please Login First" });
        const decodedData = jwt.verify(token, "njuebuipoqdjbcibwjcnowdopq");
        req.employee = await employeeModels.findById(decodedData.id);
        next();
    } catch (e) {
        res.status(500).json({
            success: false,
            error: e.message,
        });
        next();
    }
};

exports.AuthorizeRoles = (...role) => {
    return (req, res, next) => {
        if (!role.includes(req.employee.role)) {
            res.status(400).json({
                success: false,
                error: "Only Admin is Allowed to Access this route",
            });
        }
        next();
    };
};

here is my leave controller


exports.createLeave = async (req, res, next) => {
    try {
        const { reason, noOfDays } = req.body;
        const leave = await (
            await LeaveModel.create({
                reason,
                noOfDays,
                employee: req.employee._id,
            })
        ).populate({
            path: "employee",
        });
        res.status(200).json({
            success: true,
            message: "leave Has Been Submitted Successfully",
            leave,
        });
    } catch (e) {
        res.status(400).json({
            success: false,
            error: e.message,
        });
        next();
    }
};

//get All Leaves For Admin
exports.getAllLeaves = async (req, res, next) => {
    try {
        const leaves = await LeaveModel.find().populate("employee");
        if (leaves)
            return res.status(200).json({
                success: true,
                leaves,
            });
    } catch (e) {
        res.status(401).json({
            success: false,
            error: e.message,
        });
        next();
    }
};

exports.updateLeaveStatus = async (req, res, next) => {
    try {
        const leave = await LeaveModel.findByIdAndUpdate(req.params.id, req.body, {
            new: true,
            runValidators: true,
        });
        if (leave)
            return res.status(200).json({
                success: true,
                message: "Leave Status Updated Successfully",
                leave,
            });
    } catch (e) {
        return res.status(401).json({
            success: false,
            error: e.message,
        });
        next();
    }
};
exports.deleteLeave = async (req, res) => {
    try {
        const leave = await LeaveModel.findByIdAndDelete(req.params.id);
        if (leave)
            return res.status(200).json({
                success: true,
                message: "Leave Deleted Successfully",
            });
    } catch (e) {
        res.status(401).json({
            success: false,
            error: e.message,
        });
        next();
    }
};

//controller for getting single leave detail
exports.getSingleLeave = async (req, res) => {
    try {
        //getting Leave From The Leave Model By Passing Id Fetched From The Req Url Param
        const leave = await LeaveModel.findById(req.params.id).populate("employee");
        if (leave)
            return res.status(200).json({
                success: true,
                leave,
            });
    } catch (e) {
        res.status(401).json({
            success: false,
            error: e.message,
        });
        next();
    }
};

here are my leave routes

const {
    createLeave,
    getAllLeaves,
    updateLeaveStatus,
    deleteLeave,
    getSingleLeave,
} = require("../controllers/leaveController");
const {
    isAuthenticated,
    AuthorizeRoles,
} = require("../middleware/Authentication");
const Leaverouter = express.Router();

Leaverouter.post("/createleave", isAuthenticated, createLeave)
    .get(
        "/admin/getallleaves",
        isAuthenticated,
        AuthorizeRoles("admin"),
        getAllLeaves
    )
    .patch(
        "/admin/updateleave/:id",
        isAuthenticated,
        AuthorizeRoles("admin"),
        updateLeaveStatus
    )
    .delete(
        "/admin/deleteleave/:id",
        isAuthenticated,
        AuthorizeRoles("admin"),
        deleteLeave
    )
    .get(
        "/admin/leavedetails/:id",
        isAuthenticated,
        AuthorizeRoles("admin"),
        getSingleLeave
    );

module.exports = Leaverouter;

Solution

  • Do not call next() after sending a response (you have multiple places where you are doing this). You ONLY call next() when you want routing to continue so some other route handler can send a response. If you've already sent a response and then you call next() and some other route handler (or the default 404 route handler) gets called and tries to then send a second response, you will get this error.

    The particular error you are getting is caused when your code is attempting to send more than one response to the same request.