New Mongoose Schema `ERR_HTTP_HEADERS_SENT` erorr in Express.js

Viewed 69

My Goal Is

If have find any data findOne() function update current endpoint with content, if not create a new element with Schema.

Problem

If no data in db, so first if it throw me ERR_HTTP_HEADERS_SENT with console.log = 1 but if have, all in well with console.log = 3.

  try {
    const find = await endPointSchema.findOne({ uuid: uuid });
    if (!find) {
      const data = new endPointSchema({
        uuid: uuid,
        endpoint: [{ point: Endpoint, Content }],
        date: Date.now(),
      });
      await data.save();
      console.log(1);
      res.status(200).json({ message: "Succesfully Created new Breakpoint" });
      return;
    } else {
      if (!find.endpoint) {
        console.log(2);
        res.end();
        return;
      } else {
        console.log(3);
        res.end();
        return;
      }
    }
  } catch (e) {
    console.log(e);
    res.end();
    return;
  }

My Endpoint

route.post("/endpoint", AuthorizePanel, async (req, res) => {
  const { role, username, uuid } = req.user;
  if (!role && !username && !uuid) {
    res.sendStatus(401);
    return;
  }

  const { Endpoint, Content } = req.body;
  if (Endpoint === username) {
    res.status(403).json({ message: "Endpoint can not be same with your username!" });
    return;
  }

  try {
    const find = await endPointSchema.findOne({ uuid: uuid });
    if (!find) {
      const data = new endPointSchema({
        uuid: uuid,
        endpoint: [{ point: Endpoint, Content }],
        date: Date.now(),
      });
      await data.save();
      console.log(1);
      res.status(200).json({ message: "Succesfully Created new Breakpoint" });
      return;
    } else {
      if (!find.endpoint) {
        console.log(2);
        res.end();
        return;
      } else {
        console.log(3);
        res.end();
        return;
      }
    }
  } catch (e) {
    console.log(e);
    res.end();
    return;
  }
});

authorizePanel


import jwt from "jsonwebtoken";

export const AuthorizePanel = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (authHeader) {
    const token = authHeader.split(" ")[1];
    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
      if (err) {
        res.sendStatus(403)
        return
      }
      req.user = user;
      next();
    });
  }
  next();
};
2 Answers

The issue is in the auth middleware, if you look closely at the auth middleware you will notice a return statement in the jwt.verify function only returns for that function. After jwt.verify function executed the next(); function works too. To interrupt that you need to add else block to your first if block

export const AuthorizePanel = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (authHeader) {
    const token = authHeader.split(" ")[1];
    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
      if (err) {
        res.sendStatus(403)
        return
      }
      req.user = user;
      next();
    });
  } else {
    next();
  }

};

In authorizePanel, put your second next inside the else condition or remove it (if you want only authenticated users to move forward). It is being called every time.

Why I think there is an error

To simplify let's call the function with mongoose call function A.

There is a callback in your JWT verify code, so that will be called asynchronously at some point in the future.

If the user has an authentication error then the request will attempt to return a response(asynchronously) and also call function A (immediately because of the next() outside if) which will send its own response. Also if there is no error, then the flow will move to function A too. (Notice because of the other next() outside the if condition, the flow has already moved to A).

In any of these cases, there can be 2 responses sent by your server. One with JWT error and with your second function A. Or both from your function A.

The data might be saved but after that there will be an error because Headers are already sent and the server is attempting to do that again.

Related