0
localStorage.setItem('auth-token', '');

This line is where the suspected error is happening. I have read other questions that receive this error that I am going to post below. I have seen it commonly where there needs to be an async or an await somewhere, and I am missing it.

Here is the full error.

(node:2211) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:547:11)
    at ServerResponse.header (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:771:10)
    at ServerResponse.send (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:267:15)
    at checkToken (/Users/devintripp/Desktop/unt-library-system/server/controllers/user-ctrl.js:132:32)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at /Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:281:22
    at Function.process_params (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:335:12)
    at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:275:10)
    at Function.handle (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:174:3)
    at router (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:317:13)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2211) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:2211) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I have boiled it down to this code.

import React, { useState, useEffect } from 'react';
import { BrowserRouter , Route, Switch } from 'react-router-dom';
import Axios from 'axios';

import { NavBar } from './components';
import SignIn  from './components/auth/SignIn';
import Register from './components/auth/Register';
import { BooksList, BooksInsert, BooksUpdate } from './pages';
import  UserContext  from './context/UserContext'

import 'bootstrap/dist/css/bootstrap.min.css'

function App() {

    //global state for the app to use
    const [userData, setUserData] = useState({
        token: undefined,
        user: undefined
    })


    useEffect( () => {
        const checkLoggedIn = async () => {
            let token = localStorage.getItem('auth-token');
            
            console.log(token); // this prints "" to the console in the browser
            localStorage.setItem('auth-token', ''); //this code never changes the headers in chrome

            if(token === null || token === ""){
                localStorage.setItem('auth-token', '');
                token = "";
            }

            const tokenResponse = await Axios.post("http://localhost:8174/user/checkToken", null,  {headers: {"x-auth-token": token}});
            if(tokenResponse.data){
                const userRes = await Axios.get("http://localhost:8174/user/", {headers: {"x-auth-token": token}})
                setUserData({token, user: userRes.data})
            }

        }



        checkLoggedIn();
    }, []);

return (
<div></div>
);


}

also a thing to note is that the localStorage.setItem() is not setting any headers to "". It is not setting headers at all.

I have read this question: Error: Can't set headers after they are sent to the client

I am not in a body or finished state, nor am I calling res.writeHead() anywhere. I could post my backend calls to /checkToken and / if that would help.

here is my checkToken and get / calls

checkToken = async (req, res) => {
    try {
        const token = req.header("x-auth-token")
        if(!token){
            res.json(false);
        }


        const verified = jwt.verify(token, process.env.JWT_SECRET);
        if(!verified){
            return res.json(false);
        }


        const user = await User.findById(verified.id);
        if(!user){
            return res.json(false)
        }

        return res.json(true)
    } catch (err) {
        return res.status(500).json({msg: err.message});
    }
}

getUser = async (req, res) => {
    const user = await User.findById(req.user);
    // console.log(user)
    if(!user){
        console.log("no user found")
        res.json({msg: "user not found"})
    }
    res.json({
        name: user.name,
        id: user._id
    })
}

and here is where those are being called.

const express = require("express");
// const userCtrl = require("../controllers/user-ctrl");
const router = express.Router();
const UserCtrl = require("../controllers/user-ctrl");
const auth = require("../middleware/auth");





router.post('/register', UserCtrl.registerUser);
router.post('/login', UserCtrl.loginUser);
router.delete('/delete', auth, UserCtrl.deleteUser);
router.post('/checkToken', UserCtrl.checkToken);
router.get('/', auth, UserCtrl.getUser);


module.exports = router;

and lastly here is my middleware

const jwt = require('jsonwebtoken');


const auth = (req, res, next) => {

    try{
        const token = req.header("x-auth-token")
        if(!token){
            return res.status(401).json({msg: "No authentication token found, auth denied."})
        }

        
        const verified = jwt.verify(token, process.env.JWT_SECRET);
     
        if(!verified){
            return res.status(401).json({msg: "Token verification failed, auth denied."})
        }

        req.user = verified.id
        // res.end();
        next();
    } catch (err) {
        res.status(500).json({error: err.message});
    }

}


module.exports = auth;

The answer below answered the error. I wasn't returning the responses that I was sending out so it was sending multiple responses and falling through like not putting a break; at the end of a case.

localStorage however is still an issue and is unable to be set in chrome.

Devin Tripp
  • 147
  • 10
  • Voting to close; have you read the error message or googled it? See [Error: Can't set headers after they are sent to the client](https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client) – Codebling Dec 29 '20 at 17:33
  • yes i have done both. It is not related to my question – Devin Tripp Dec 29 '20 at 17:34
  • I believe it **is** related to your error. You are showing server-side logs but suggesting that the error is in client-side code -- why do you think that? – Codebling Dec 29 '20 at 17:35
  • because if I comment out the localStorage.setItem('auth-token', "") then the server error does not appear – Devin Tripp Dec 29 '20 at 17:37
  • It is related to the error but it is not the same. – Devin Tripp Dec 29 '20 at 17:37
  • Is it possible that whatever you're commenting out may be changing the request or not sending it? Regardless, since you acknowledge that the issue is server-side, shouldn't we focus on fixing it there? The code above may be *triggering* the error, but it isn't *causing* it. – Codebling Dec 29 '20 at 17:41

1 Answers1

1

It is the same issue mentioned in comments & close request.

The Problem

You try to send multiple responses to the same request. Trying to send multiple responses to the same request is what causes the Express error.

This happens in your getUser code as well as in your checkToken code.

  • getUser attempts to send multiple responses if the condition !user is true (if user evaluates to false).
  • checkToken will attempt to send multiple responses if one of !token, !verified or !user is true.
Codebling
  • 10,764
  • 2
  • 38
  • 66