DjangoRocks
DjangoRocks

Reputation: 14198

Error: Can't set headers after they are sent to the client

I'm fairly new to Node.js and I am having some issues.

I am using Node.js 4.10 and Express 2.4.3.

When I try to access http://127.0.0.1:8888/auth/facebook, i'll be redirected to http://127.0.0.1:8888/auth/facebook_callback.

I then received the following error:

Error: Can't render headers after they are sent to the client.
    at ServerResponse.<anonymous> (http.js:573:11)
    at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
    at ServerResponse.writeHead (http.js:813:20)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
    at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
    at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
    at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
    at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
    at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
    at EventEmitter._tickCallback (node.js:126:26)

The following is my code:

var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"

var cookieSecret = "node";     // enter a random hash for security

var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();


app.configure(function(){
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({secret: cookieSecret}));
    app.use(auth([
        auth.Facebook({
            appId : fbId,
            appSecret: fbSecret,
            callback: fbCallbackAddress,
            scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
            failedUri: '/noauth'
        })
    ]));
    app.use(app.router);
});


app.get('/auth/facebook', function(req, res) {
  req.authenticate("facebook", function(error, authenticated) {
    if (authenticated) {
      res.redirect("/great");
      console.log("ok cool.");
      console.log(res['req']['session']);
    }
  });
});

app.get('/noauth', function(req, res) {
  console.log('Authentication Failed');
  res.send('Authentication Failed');
});

app.get('/great', function( req, res) {
  res.send('Supercoolstuff');
});

app.listen(8888);

May I know what is wrong with my code?

Upvotes: 1235

Views: 2154607

Answers (30)

Ashish Kumar
Ashish Kumar

Reputation: 223

The issue is, multiple modification of header of res(Response) is happening in the code. Which isn't allowed because express sends the data to client when the first invocation happens. So the second one fails. If you can bypass to having only 1 header per case, it will resolve the issue. It can be done Via conditional statements or returning once headers are assigned or not setting errors until you have completely processed till the end of code (whichever applies best)

I was getting the same Error "ERR_HTTP_HEADERS_SENT" for the following code:

const createPrice = async function (request, response) {
  const data = request.body;
  var maxID = 9999;
  const result = await pool.query("SELECT MAX(id) FROM pricing");
  maxID = result.rows[0].max + 1;
  pool.query(
    "Insert into pricing (id, price, discounts) values ($1, $2, $3) RETURNING *",
    [maxID, data.price, data.discounts,],
    (error, results) => {
      if (error) {
        throw error;
      }
      response.status(201).send(`Rate Card ID: ${maxID} Created`);
          }
        }
      );
    };

To me it seems like the issue was I am handling the error in my middleware, so what was happening was the body of the response was getting set in 2 places, first in the throw error; and secondly in response.status(201).send();

I think the minimum change required to get my code to work was to put an else and put my response.send() inside it. So only one of the two setting of data to request works.

Somehow, putting a return or headerSent check alone didn't work for me. But I ended up using a combination of above solutions for better handling of the issue. Here, my final change:

(error, results) => {
  if (error) {
    throw error;
  } else if (!response.headersSent) {
    // if doesn't sent yet
    return response
      .status(201)
      .send(`Rate Card ID: ${data.maxID} Created`);
  }
}

Upvotes: 0

nasmus shahadat
nasmus shahadat

Reputation: 31

Do not use multiple res in one api. Just use res one time and this problem will be solved.

Upvotes: 2

Brijal Kansara
Brijal Kansara

Reputation: 191

I had the same issue. For me i had 2 res.json(event) was giving this error to me.

res.json(savedEvent);
res.json({ event });

We should pass only single response will work.

res.json(event);

Upvotes: 6

otumian Empire
otumian Empire

Reputation: 39

I had the same error using postman. I noticed that the request body (data) was improperly formatted. The error was pointing to the middleware I passed on the routes. When I remove one middleware, it then means to the next.

Upvotes: 1

holabisii
holabisii

Reputation: 65

I faced the error for a couple of days and found out that it was my jwt that got expired, in that scenerio it could not set headers.

check your jwt expiration date

Upvotes: 1

Emmanuel Benson
Emmanuel Benson

Reputation: 408

I simply add the return keyword like: return res.redirect("/great"); and it worked!

Upvotes: 23

Auguste
Auguste

Reputation: 2201

In my case, I had to add the .then() method of Promise to chain on the response. So my code looks like below:

 app.post(`${api}/categories`, (req, res) => {
const category = new Category({
    ....
});
category.save().then(c => {
    res.status(201).json(c)
}).catch((err) => {
    res.status(500).json({
        ...
    })
});

})

Upvotes: 1

GoldPaintedLemons
GoldPaintedLemons

Reputation: 492

Evidently this can happen for a multitude of reasons. Many are complex, but my case was a pretty simple mistake.

Check that you have the right form method. The default is GET, and I somehow forgot to specify. As one can imagine, my GET route logic did a poor job handling the req.body data that was designed to be parsed by my POST route logic.

Upvotes: 0

M Fuat
M Fuat

Reputation: 1440

In my case, it was a global interceptor that was setting the no-cache header.

Upvotes: 0

Marvin
Marvin

Reputation: 754

The problem was exist from /auth/facebook route to make things ease to understand, once that you sent a response already from the client, you must NOT set any other functions below for next successor block, it is also related on being Synchronous of JavaScript,

for deep understanding, it is looks like this code;

async function getRequest(){
   let data = await API.get();
   return data;
   let json = data.json(); // will not read this line
}

on your case, console.log("ok cool."); and console.log(res['req']['session']) must be put before res.redirect("/great")

enter image description here

Hope it make sense, Welcome :)

Upvotes: 3

Rajanboy
Rajanboy

Reputation: 2682

sometimes only writing res.status(200).json({success: 'user authenticated'); is not enough. For hours , i found we have to return return response sometimes. Like this

return res.status(200).json({success: 'user authenticated');

so that It can terminate whenever in some conditional statement and doesn't run other .

Upvotes: 3

Johan Tamayo
Johan Tamayo

Reputation: 51

I got the same error and found my solution was to change all of my sendStatus lines of code to status.

// old
res.sendStatus(200);

// new 
res.status(200);

Upvotes: 2

Shallon Kobusinge
Shallon Kobusinge

Reputation: 575

I had the issue this is what I was doing

const user  = await User.findOne({_id: req.params.id})

so I had to change findOne to findById and it did the trick for me

const user = await User.findById(req.params.id)

Upvotes: 1

genericUser
genericUser

Reputation: 7188

A newer version of Node supports res.headersSent boolean expression. You can use it to validate whether you already sent a response:

if (!res.headersSent) // if doesn't sent yet
    res.status(200).send({ "message": "This is a message" })

Note! Although this works and answers the question, it's not the right way to solve the problem, and is not recommended!

Sending a response more than once indicates that you have a problem in your code that should be fixed (It's the same as using two return statements, one after another, in your function. it's a bug).

Upvotes: 6

Engin Karataş
Engin Karataş

Reputation: 55

If you uses two of res.end() function in one api call, this error shows

for example

  app.post("/auth", function (request, res) {
    var username = request.body.username;
    var password = request.body.password;
    if (username && password) {
      let sql =
        "SELECT username, worker_name, worker_surname, id FROM workers where username = ? AND password=?";
      con.query(sql, [username, password], function (error, results, fields) {
        if (results.length > 0) {
          res.status(200).send(results);
          res.end();
  
        }
        res.status(404).send("Incorrect Username and/or Password!");
      });
    } else {
      res.send("Please enter Username and Password!");
    }
    res.end();

  });

Upvotes: 3

Rupak
Rupak

Reputation: 541

Check your code. For me, I used res.status twice in the same if statement. First one set the header status and the second one tried to change it, which caused the problem.

Upvotes: 2

SanRaph
SanRaph

Reputation: 369

In my case, this is recurring when I don't make a function that is running against a mongodb schema an async function like this technicianAuthSchema.methods.matchPasswords = function(password) { return await bcrypt.compare( password, this.password ); }; I get this Logged error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client instead of technicianAuthSchema.methods.matchPasswords = async function(password) { return await bcrypt.compare( password, this.password ); }; It is asynchronous because the this.password is coming from the object this function is running against which we are pulling from the database.

Upvotes: 1

KNDheeraj
KNDheeraj

Reputation: 852

Please check if your code is returning multiple res.send() statements for a single request. Like when I had this issue....

I was this issue in my restify node application. The mistake was that

switch (status) {
    case -1:
      res.send(400);
    case 0:
      res.send(200);
    default:
      res.send(500);
}

I was handling various cases using switch without writing break. For those little familiar with switch case know that without break, return keywords. The code under case and next lines of it will be executed no matter what. So even though I want to send single res.send, due to this mistake it was returning multiple res.send statements, which prompted

error: can't set headers after they are sent to the client.

Which got resolved by adding this or using return before each res.send() method like return res.send(200)

switch (status) {
    case -1:
      res.send(400);
      break;
    case 0:
      res.send(200);
      break;
    default:
      res.send(500);
      break;
}

Upvotes: 7

Farbod Aprin
Farbod Aprin

Reputation: 1186

Please search if in your app.get to not set status before res.send("your result");

I just removed :

res.sendStatus(200);

and response works after that !!!

res.send("your result");

Upvotes: 5

HandyPawan
HandyPawan

Reputation: 1116

Process.env does not change, so it must not be used for accessing per-request environment variables whose values may change on a per-request basis. So, if the user spawns an application process, but not as part of handling a request, then that application process will not have per-request environment variables stored inside OS-level environment variables. So, use this code to store process env and your program run successfully.

    const port = process.env.PORT || 2000;
    
    app.listen(port,()=>{
        console.log("Server running at port 2000");
    })

Upvotes: 1

Mohammed Ramadan
Mohammed Ramadan

Reputation: 723

there is something else that cause this error and it is when you do not add return keyword in front of res.send, res.json, etc...

Upvotes: 8

Nagender Pratap Chauhan
Nagender Pratap Chauhan

Reputation: 2204

error find by itself after a RND :

1) my error code :

return res.sendStatus(200).json({ data: result });

2) my success code

return res.status(200).json({ data: result });

the difference is that i used sendStatus() instead of status().

Upvotes: 24

Hasan Sefa Ozalp
Hasan Sefa Ozalp

Reputation: 7204

In my case, In a loop, I put res.render() so might have been tried to call multiple times.

Upvotes: 0

Sina Abedi
Sina Abedi

Reputation: 2401

I had the same problem which was caused by mongoose.

to fix that you must enable Promises, so you can add : mongoose.Promise = global.Promise to your code,which enables using native js promises.

other alternatives to this soloution is :

var mongoose = require('mongoose');
// set Promise provider to bluebird
mongoose.Promise = require('bluebird');

and

// q
mongoose.Promise = require('q').Promise;

but you need to install these packages first.

Upvotes: 1

Mike K
Mike K

Reputation: 6509

My issue was that I had a setInterval running, which had an if/else block, where the clearInterval method was inside the else:

      const dataExistsInterval = setInterval(async () => {
        const dataExists = Object.keys(req.body).length !== 0;
        if (dataExists) {
          if (!req.files.length) {
            return res.json({ msg: false });
          } else {
              clearInterval(dataExistsInterval);
            try {
            . . .

Putting the clearInterval before the if/else did the trick.

Upvotes: 0

trustidkid
trustidkid

Reputation: 557

I got a similar error when I tried to send response within a loop function. The simple solution was to move the

res.send('send response');

out of the loop since you can only send response header once.

https://www.tutorialspoint.com/nodejs/nodejs_response_object.htm

Upvotes: 2

Badr Bellaj
Badr Bellaj

Reputation: 12871

This error happens when you send 2 responses. For example :

if(condition A)
{ 

      res.render('Profile', {client:client_});

}

if (condition B){

      res.render('Profile', {client:client_});
    }
  }

Imagine if for some reason condition A and B are true so in the second render you'll get that error

Upvotes: 17

Krishnadas PC
Krishnadas PC

Reputation: 6539

If you are using callback functions use return after the err block. This is one of the scenarios in which this error can happen.

userModel.createUser(data, function(err, data) {
    if(err) {
      res.status = 422
      res.json(err)
      return // without this return the error can happen.
    }
    return res.json(data)
  })

Tested on Node version v10.16.0 and express 4.16.4

Upvotes: 13

Naved Ahmad
Naved Ahmad

Reputation: 821

It is very likely that this is more of a node thing, 99% of the time it's a double callback causing you to respond twice, or next()ing twice etc, damn sure. It solved my problem was using next() inside a loop. Remove the next() from the loop or stop calling it more than one times.

Upvotes: 3

coder
coder

Reputation: 906

All I had to do in case of this error was res.end().

 auth.annonymousOnly = function(req, res, next) {
 // add other task here   
   res.end();    
  };

The other problem you could be facing is there is code after res.json and res. write. In this case, you need to use return to stop execution after that.

 auth.annonymousOnly = function(req, res, next) {

  if(!req.body.name)
  {
    res.json({error:"some error"});
    return;
  }
  let comp = "value"; // this is the code after res.json which may cause some problems so you have to use return 
};

Upvotes: -1

Related Questions