Error Cannot set headers after they are sent to the client - Issue Tracker

I’m passing all the functional tests for this project except one. I get an error

 1) Functional Tests PUT /api/issues/{project} => text One field to update:
2:08
     Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I goggle the error and understand it a little but not enough to see what’s wrong. The other tests pass and my code for those tests looks the same as the one that fails. The failing one is for

test('One field to update',
  suite('PUT /api/issues/{project} => text', function() {
      
      test('No body', function(done) {
        chai.request(server)
          .put("/api/issues/test")
          .send({_id: "kyPXsHr_z"})
          .end( function (err, res) {
            assert.equal(res.status, 200);
            assert.equal(res.text, "no updated field sent");
          done();
      })});
      
      test('One field to update', function(done) {
        chai.request(server)
          .put("/api/issues/test")
          .send({_id: "hmv-iLuCv", 
                 issue_title: "title 1"})
          .end( function (err, res) {
            assert.equal(res.status, 200);
            assert.equal(res.text, "successfully updated");
          done();
      })});
      
      test('Multiple fields to update', function(done) {
        chai.request(server)
          .put("/api/issues/test")
          .send({_id: "kyPXsHr_z", 
                 issue_title: "title",
                 issue_text: "text"})
          .end( function (err, res) {
            assert.equal(res.status, 200);
            assert.equal(res.text, "successfully updated");
          done();
      })});
      
    });

My full code here .
The project is for the Issue Tracker
https://learn.freecodecamp.org/information-security-and-quality-assurance/information-security-and-quality-assurance-projects/issue-tracker

I rewrote this part

test('One field to update', function(done) {
        chai.request(server)
          .put("api/issues/test")
          .send({_id: "hmv-iLuCv",
                issue_title: "title 1"})
          .end( function(err, res) {
            assert.equal(res.status, 200);
            assert.equal(res.text, "successfully updated");
          done();
        })
      });

I don’t see how it is different from what I had before but now the error is

Uncaught TypeError: Cannot read property 'status' of undefined

I don’t understand how ‘status’ can be undefined when it is used in the same way in the rest of the code?

Original:
.put("/api/issues/test")

Updated:
.put("api/issues/test")

Is something missing in your updated code?

1 Like

I’m just jumping in the middle here. Your error message isn’t saying that status is undefined. It is saying that res is undefined.

You need to guard yourself against errors, by first checking if err is defined, if it isn’t then you’ll also want to make sur res is defined such as

if (err) {
 // Put whatever you want here to handle errors
} else if (res) {
// If there is no err, then you should be able to assume there is a res, 
// but I always check just in case.
} 

Hope this helps.

PS: Headers always have to be the first thing sent in an HTTP response and when you do, its like dropping an envelope in the post office, once you send headers, they are gone and cannot be modified.

1 Like

I see, dumb mistake. Puts my error back to

Cannot set headers after they are sent to the client

@shadowfox476 thanks, that makes sense because when I rewrote the code I left out the first forward slash. Good tip on checking if (err).

So I’m back to having the original error message. I’ve read some more on it and I still don’t understand where the header is set and where it is trying to reset the header? The error message points to the line in my original post. I don’t see what is different in that test from the other tests to cause the error?

The problem must be somewhere in here

.put(function (req, res){
      var project = req.body; 
      var id = project._id;
      var updates = {
        issue_title: project.issue_title,
        issue_text: project.issue_text,
        created_by: project.created_by,
        assigned_to: project.assigned_to,
        status_text: project.status_text,
        open: project.open
      };
      if (!project.issue_title) { delete updates.issue_title}
      if (!project.issue_text) { delete updates.issue_text}
      if (!project.created_by) {delete updates.created_by}
      if (!project.assigned_to) {delete updates.assigned_to}
      if (!project.status_text) {delete updates.status_text}
      if (!project.open) {delete updates.open}
    
      if (Object.keys(updates).length === 0) {
        res.send("no updated field sent");
      } else {
        updates.updated_on = new Date();
      };
    
      Issue.findOneAndUpdate({_id: id}, updates, {new: true}, function(err, doc) {
        if (err) { 
          console.log(err); 
        } else if (!doc) {
          res.send("could not update " + id)
        } else {
          console.log(doc);
          res.send("successfully updated");
        }
      })
    
    })

hi eoja
use return res.send()
because res alone do not stop execution of your code
even if the if statement is true you still execute the findOneAndUpdate function

2 Likes

@yakhousam thanks for the help! That does fix the problem because findOneAndUpdate was executing no matter what. Late last night I realized it had something to do with the if/else statements, so after trying your suggestion this morning I also put findOneAndUpdate within the else part of if/else statement so it only executes if there was an update field sent. So just moving one curly bracket further down the code worked also.

1 Like

Thank you so much man, saved my day!

1 Like