Nunjucks: Error: Can't set headers after they are sent. (Express 4)

Created on 27 Jan 2016  路  18Comments  路  Source: mozilla/nunjucks

I am getting this when using with express 4 and express-flash.

I used with swig and all worked.

Here is failing when render is called, it return the html and then fails.

Wed, 27 Jan 2016 21:41:57 GMT connect:redis GET "5cg6LbHdXhWuUnKXYWL6kPNRfeN1TN9u"
Wed, 27 Jan 2016 21:41:57 GMT connect:redis SET "yWgxdkWw0rTHBpi-RuzqRkYLbOUQGdYG" {"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"},"flash":{}} ttl:86400
_http_outgoing.js:335
    throw new Error('Can\'t set headers after they are sent.');
    ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
    at ServerResponse.header (/Users/carlitux/Projects/project/node_modules/express/lib/response.js:718:10)
    at ServerResponse.send (/Users/carlitux/Projects/project/node_modules/express/lib/response.js:163:12)
    at done (/Users/carlitux/Projects/project/node_modules/express/lib/response.js:957:10)
    at /Users/carlitux/Projects/project/node_modules/nunjucks/src/environment.js:22:23
    at RawTask.call (/Users/carlitux/Projects/project/node_modules/asap/asap.js:40:19)
    at flush (/Users/carlitux/Projects/project/node_modules/asap/raw.js:50:29)
    at doNTCallback0 (node.js:419:9)
    at process._tickCallback (node.js:348:13)
express

Most helpful comment

I don't use Express, so I probably won't be able to be much help here. Usually that kind of error is because something is sending output to the client earlier than expected? I don't have any idea why Nunjucks would be different from Swig in that regard, though.

All 18 comments

I don't use Express, so I probably won't be able to be much help here. Usually that kind of error is because something is sending output to the client earlier than expected? I don't have any idea why Nunjucks would be different from Swig in that regard, though.

@carljm looks like that is the issue if I use

 res.end() 

Instead of

 res.render('template') 

All works fine. looks like asap lib and /Users/carlitux/Projects/project/node_modules/nunjucks/src/environment.js:22:23 are calling the callback before what is expected.

connect/express flash is simple:

module.exports = function flash(options) {
  options = options || {};
  var safe = (options.unsafe === undefined) ? true : !options.unsafe;

  return function(req, res, next) {
    if (req.flash && safe) { return next(); }
    req.flash = _flash;
    next();
  }
}

So when this middleware calls next(); the final middleware is calling res.render... fails.

nevermind express-flash just tested with simple middleware:

function middleware (req, res, next) {
  return next();
}

and it is failing.

Hey guys I hope this helps:

The error happens in this workflow:

1.- nunjucks render template and send.
2.- if any async errors happends latter express tries to render the error template and send (here is the error)

In the project I am working now the session middleware is failing when tries to save the session where render was called and tries to render the second one.

This has happened to me in Express 4 while attempting to create a nunjucks env to attach filters to, without express-flash.

In Express' typical app.js setup, I've done this for hooking up templates/views to be rendered w/ nunjucks:

// view engine setup
app.set('views', path.join(__dirname, 'views'));

var env = nunjucks.configure(app.get('views'), {
    autoescape: true,
    express:    app,
    watch:      true
});

env.addFilter('minify', function(asset) {
    var ext = "." + asset.split('.').pop();

    if(app.get('env') === 'production' || app.get('env') === 'staging') {
        asset = asset.replace(ext, ".min" + ext);
    }

    return asset;
});

env.addFilter('asset', function(assetpath) {
    var asset_url = Asset.link || "/";
    return asset_url + assetpath;
});

app.set('view engine', 'nunjucks');

Removing the filters and not setting nunjucks.configure to env solved this problem for me, but I like to have filters to do things on template render...

{% if true %} {% include './test.html'%} {% endif%}
test.html:
{{ utils.test('testesttestesttestesttestest') }}

utils.test = function(){ syntax error }

so will happen
_http_outgoing.js:346 throw new Error('Can\'t set headers after they are sent.'); ^ Error: Can't set headers after they are sent.

Not a fix, but if you want to see the error causing this, add the following code to the end of the file that starts the application (eg node server.js)

EDIT:

if(process.env.NODE_ENV !== 'production') {
  process.once('uncaughtException', function(err) {
    console.error('FATAL: Uncaught exception.');
    console.error(err.stack||err);
    setTimeout(function(){
      process.exit(1);
    }, 100);
  });
}

I have this problem too. When refresh twice quickly. Then happened
Any solution?

^This is a bug I feel anyone using express would run into. I too have the same issue.

If you have the template render after passing through middleware and the page is refreshed too quickly. The page errors and the app errors.

because you might send no less than 2 times response.

like my code:

  getAllTables().then((data) => res.send(data)).catch((err) => console.log(err));
  next();

I used Promise.then() and my function next() goes before my res.send(), so I had response more than 1 times to front-end.
like me, you can write like this.

  getAllTables().then((data) => {
    res.send(data);
    return next();
  }).catch((err) => console.log(err));

@xingbofeng you're right. I had figured out my issue. The thing is prior to using nunjucks I didnt get this error. So I assumed it was something wrong on nunjucks end especially when I seen this ticket.

The issue was in my authentification middleware:

exports.isAuthenticated = (req, res, next) => { if(!req.session.username) res.redirect('/'); next(); };

I had changed it to:

exports.isAuthenticated = (req, res, next) => { if(!req.session.username){ res.redirect('/'); }else{ next(); } };

I was trying out nunjucks because I needed a robust templating language that used blocks. I dont like Jade/Pug. I've worked with Smarty which is for Php. Nunjucks was very similar and I had no learning curve.

If you add this code to your project probably works ...

const server = http.createServer((req,res)=>{ res.setHeader('Content-Type', 'text/html'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('MehdiFilban solved this problem\nYour Header is set NOW\nGOOD LUCK...'); }).listen(port,()=>{ console.log('your app is started'); });

Happened with me while I was sending response twice and not using return with one of them.

````
router.get('/me', auth, async (req, res) => {
const user = await User.findById(req.user._id);
if(!user) res.status(400).send("User not Found");

res.send(user)
})
````

Here when user is not found res.send() is called twice so using return fixed this error.

````
router.get('/me', auth, async (req, res) => {
const user = await User.findById(req.user._id);
if(!user) return res.status(400).send("User not Found");

res.send(user)
})
````

So you can check if res.send() is not called twice as this is one case of getting this error.

Hi,
happen to me recently by missing 'Code' in statusCode:

  router.get('/:username', (req, res) => { 
   try {
       const options = {
             uri:`{https://api.myurl.com/${req.params.username}`,
             method: 'GET',
             headers: { 'user-agent' : 'node.js' }
            }

 console.log(options);

         request(options, (error, response, body) => {
              if(error) console.error(error);
                   if (response.statusCode !== 200 ){
                    return  res.status(400).json({ msg: 'Username not found' });
            }   
            res.json(JSON.parse(body));
            });

@nvittet not sure if this is the same case:

APIHelper.sendErrorMesage = function (req, res, error) {
            var errorCode = 400;
            var errorHint = '';
            if (error.code) errorCode = error.code;
            switch (errorCode) {
                case 401:
                    errorHint =SDK.Models.ErrorHint.MXM_ERROR_HINT_NOTAUTHORIZED;
                    break;
                case 400:
                    errorHint =SDK.Models.ErrorHint.MXM_ERROR_HINT_INCORRECTFORMAT;
                    break;
                case 404:
                    errorHint =SDK.Models.ErrorHint.MXM_ERROR_HINT_NOT_FOUND;
                    break;
                case 503:
                case 500:
                    errorHint =SDK.Models.ErrorHint.MXM_ERROR_HINT_SERVERERROR;
                    break;
                default:
                    errorHint =SDK.Models.ErrorHint.MXM_ERROR_HINT_INCORRECTFORMAT;
                    break;
            }
            var errorMessage = APIHelper.createErrorMessage(errorCode, errorHint, error.message);
            if (error.code == 503) { //   Retry-After: 300 seconds
                var retryAfterTimeout = 60 * 5;
                res.setHeader('Retry-After', retryAfterTimeout);
            }
            res.status(errorCode);
            res.send(errorMessage);
            return errorMessage;
        } //sendErrorMesage

I get that error and stack trace reports line res.send(errorMessage); so just after the res.status

Here is the code that was causing the problem for me:

db.each("SELECT * FROM ASSIGNMENTS WHERE EMAIL=?", [email], (err, row) => {
        if(err) {
            console.log("failed to retrieve assignments:", err)
            //res.send("error")
        }
        console.log("successfully retrieved assignments:")
        console.log("row:", row)
        res.json({assignments: row})
    })
    db.close()
})

When I moved the res.json() line to the end of the function, it fixed the problem.

Hey guys!. I am stuck due this error in Expressjs4. Please help me.

(node:27251) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:543:11)
at ServerResponse.writeHead (_http_server.js:274:21)
at Object.download (/Users/cescobar.it/gobynet-api/controllers/contributorCtrl.js:119:17)

**server.js**:  app.get('/contributor/:id/picture', function(req, res) { ContributorCtrl.download(req,  res);} );
------
**ControllerCtrl.js:**

 download: async function(req, res, next) {
        let statusCode = 200;
        let contributor = [];
        try {
            contributor = await ContributorVO.download(ContributorCtrl.cfg.database, [req.params.id]);
            statusCode = contributor[0].length > 0 ? 200 : 404;
            res.status(statusCode).json(contributor[0].length > 0 ? contributor[0] : {});
            const picture = contributor[0].picture != null ? contributor[0].picture : 'unknown-pic.png';
            //console.log(picture);

            //res.setHeader('Content-Type', 'image/jpg');
            //res.setHeader('Content-Type', 'image/png');
            //res.setHeader('Access-Control-Allow-Origin', '*');
            res.writeHead(200, {
                'Access-Control-Allow-Origin': '*',
                'Content-Type': 'image/png',
                'Content-Type': 'image/jpg',
                'Content-Length': picture.length
            });

            res.download('./public/uploads/images/contributors/' + picture);
        }
        catch(e) {
            console.log(e.code, ' ', e.fatal);
            console.log(e.message);
            statusCode = 500;
            res.status(statusCode).json(contributor[0].length > 0 ? contributor[0] : {});
            return;
        }
    }
Was this page helpful?
0 / 5 - 0 ratings