Typescript in node - Error cannot set Headers after they are send to the client

I get this error in my login file, when I test it with postman. I had to modify several things for typescript. Without typescript this file always has worked. So I could imagine, that it depends on the typescript elements or on the userinterface, where I have set “_doc”, because otherwise I get an error, that typescript not know what that is. So I put both snippets in this question. Thanks for your help.
My login:

authRouter.post('/login', async (request:Request, response:Response)=>{
    let sec:string = process.env.JWT_SEC as string;
    try{
        const user = await User.findOne({username:request.body.username});

        !user && response.status(401).json("Wrong credentials");

        const hashedPassword = CryptoJS.AES.decrypt(user?.password, process.env.PASS_SEC);

        const originalPassword = hashedPassword.toString(CryptoJS.enc.UTF8);
        const inputPassword = request.body.password;
        originalPassword !== inputPassword && response.status(401).json("Wrong Password")
        const accessToken = jwt.sign(
            {id: user!._id,
             isAdmin:user!.isAdmin,
            },
            sec,
            {expiresIn:"30d"}
        )
        const {password, ...others} = user?._doc;
        response.status(200).json({...others, accessToken});
    } catch(error:any){
        response.status(401)
        throw new Error(error)
    }
});

My mongoose.model:

export interface UserDocument extends mongoose.Document{
    vorname:string;
    nachname:string;
    username:string;
    email:string;
    street:string;
    number:string;
    plz:number;
    city:string;
    password:string;
    isAdmin:boolean;
    createdAt: Date;
    updatedAt: Date;
    _doc?: any;
    organization: Types.ObjectId;
  }
const UserSchema = new mongoose.Schema<UserDocument>({
    vorname:{type:String, required:true},
    nachname:{type:String, required:true},
    username:{type:String, required:true },
    email:{type:String, required:true },
    street:{type:String, required:true },
    number:{type:String, required:true },
    plz:{type:Number, required:true },
    city:{type:String, required:true },
    password:{type:String, required:true },
    isAdmin:{type:Boolean, default:false},
    organization: { type: mongoose.Schema.Types.ObjectId, ref: 'Organization' }
}, 
    {timestamps:true}
)

const User = mongoose.model<UserDocument>('User', UserSchema);

Hello!

I want you to copy and paste this example on repl.it (or fork this one):

const express = require('express');
const app = express();

app.use('/api/test', (req, res) => {
  const testString = 'is_true';

  if (testString === 'is_true') {
    res.status(404).json({
      status: 'OK',
      error: 'The string comparison is true',
    });
  }

  res.status(200).json({
    status: 'ERROR',
    error: '',
  });
});

app.listen(() => {
  console.log('App listening');
});

Run/execute the project and then try to access the endpoint /api/test and see what is logged to the console.

Can you spot the problem? This is the same problem you have: the response object does not interrupt the execution of the program

Thanks for your response, skaparate. I have paste that in repl.it, but I never worked with repl.it, so I not know exactly what I should do. For my issue, I want to add, that the register works. I have it in the same auth file. And Postman throws me my error “wrong password” at the same time. I logged all const, and have seen that originalPassword and inputPassword are not equal, but I don’t know why, because I used this function several times without typescript and it has always worked. And the password is exactly that, what I send in register, because I have copied it.

I changed originalPassword !== inputPassword into
originalPassword != inputPassword But I have the same error.

You have those lines of code, right?

When a program runs, it does run from top to bottom first. So, the first time it runs (when you start the application), it will configure itself and start handling the routes you define.

After it has started and you consume an endpoint (/login), the route is executed just like that too: from top to bottom.

So, if we were the ones to process the route, these would be the steps:

  1. We find one user that matches the specified username
  2. We check if there were results for the user, otherwise we tell the client that there was an error (401) and a text.
  3. Hash the password
  4. Compare to the original password (read from the database)
  5. Return a status OK (200) and a JSON object.
  6. In case of an error, we would return a 401 and throw an exception.

Your problem is at the second point. If you read my first response, I said: the response object does not stop the execution of the program

That means that the steps 3 through 5 (and/or 6, in case of an error) are still executed and once you reach step 5 (or 6), the headers have already been sent.

See?

Try this instead:

if (!user) {
  return res.status(401).json('...');
}

I think, I understand what you mean and I know that the program runs from top to bottom, but the user is found and so it ignores the return. I tried what you have suggested and tried as next:

 if(originalPassword != inputPassword){
            return response.status(401).json("Wrong password");
} else {
        const accessToken = jwt.sign(
            {id: user!._id,
             isAdmin:user!.isAdmin,
            },
            sec,
            {expiresIn:"30d"}
        )
        const {password, ...others} = user?._doc;
        response.status(200).json({...others, accessToken});
        }

The error is now fixed but it throws me that error :" wrong password" . But the log of inputPassword gives me back the correct password out of the register. Because I copied it and only have deleted the fields, that I not need for login.