Меню

Cannot set headers after they are sent to the client ошибка

Some of the answers in this Q&A are wrong. The accepted answer is also not very «practical», so I want to post an answer that explains things in simpler terms. My answer will cover 99% of the errors I see posted over and over again. For the actual reasons behind the error take a look at the accepted answer.


HTTP uses a cycle that requires one response per request. When the client sends a request (e.g. POST or GET) the server should only send one response back to it.

This error message:

Error: Can’t set headers after they are sent.

usually happens when you send several responses for one request. Make sure the following functions are called only once per request:

  • res.json()
  • res.send()
  • res.redirect()
  • res.render()

(and a few more that are rarely used, check the accepted answer)

The route callback will not return when these res functions are called. It will continue running until it hits the end of the function or a return statement. If you want to return when sending a response you can do it like so: return res.send().


Take for instance this code:

app.post('/api/route1', function(req, res) {
  console.log('this ran');
  res.status(200).json({ message: 'ok' });
  console.log('this ran too');
  res.status(200).json({ message: 'ok' });
}

When a POST request is sent to /api/route1 it will run every line in the callback. A Can’t set headers after they are sent error message will be thrown because res.json() is called twice, meaning two responses are sent.

Only one response can be sent per request!


The error in the code sample above was obvious. A more typical problem is when you have several branches:

app.get('/api/company/:companyId', function(req, res) {
  const { companyId } = req.params;
  Company.findById(companyId).exec((err, company) => {
      if (err) {
        res.status(500).json(err);
      } else if (!company) {
        res.status(404).json();      // This runs.
      }
      res.status(200).json(company); // This runs as well.
    });
}

This route with attached callback finds a company in a database. When doing a query for a company that doesn’t exist we will get inside the else if branch and send a 404 response. After that, we will continue on to the next statement which also sends a response. Now we have sent two responses and the error message will occur. We can fix this code by making sure we only send one response:

.exec((err, company) => {
  if (err) {
    res.status(500).json(err);
  } else if (!company) {
    res.status(404).json();         // Only this runs.
  } else {
    res.status(200).json(company);
  }
});

or by returning when the response is sent:

.exec((err, company) => {
  if (err) {
    return res.status(500).json(err);
  } else if (!company) {
    return res.status(404).json();  // Only this runs.
  }
  return res.status(200).json(company);
});

A big sinner is asynchronous functions. Take the function from this question, for example:

article.save(function(err, doc1) {
  if (err) {
    res.send(err);
  } else {
    User.findOneAndUpdate({ _id: req.user._id }, { $push: { article: doc._id } })
    .exec(function(err, doc2) {
      if (err) res.send(err);
      else     res.json(doc2);  // Will be called second.
    })

    res.json(doc1);             // Will be called first.
  }
});

Here we have an asynchronous function (findOneAndUpdate()) in the code sample. If there are no errors (err) findOneAndUpdate() will be called. Because this function is asynchronous the res.json(doc1) will be called immediately. Assume there are no errors in findOneAndUpdate(). The res.json(doc2) in the else will then be called. Two responses have now been sent and the Can’t set headers error message occurs.

The fix, in this case, would be to remove the res.json(doc1). To send both docs back to the client the res.json() in the else could be written as res.json({ article: doc1, user: doc2 }).

Express is a JavaScript framework for Node.js. It handles a Web application’s front end and back-end, calling the appropriate event handlers and making the necessary database conversions by utilizing various Node modules whenever it receives a request from an user. Express is one of the most popular web frameworks out there, downloaded more than 10 million times as of this writing.

The beauty of Express lies in its simplicity: it offers no opinionated work but has just enough to get your job done fast with at least some degree of conciseness, which is perfect for beginners who are not yet familiar with Node or JavaScript and just want something simple and easy to work with.

“Can’t set headers after they are sent to the client” is one of the most common errors in Express.js. This error occurs when you sent a response to the client before and then you try to send the same response again. This article is going to show you a few ways you can get rid of “Can’t set headers after they are sent to the client” error in Express.js.

The res object in Express is a subclass of Node.js’s http.ServerResponse . You are allowed to call res.setHeader(name, value) as often as you want until you call res.writeHead(statusCode). After writeHead, the headers are baked in and you can only call res.write(data), and finally res.end(data).

The error “Error: Can’t set headers after they are sent.” means that you’re already in the Body or Finished state, but some function tried to set a header or statusCode. When you see this error, try to look for anything that tries to send a header after some of the body has already been written. For example, look for callbacks that are accidentally called twice, or any error that happens after the body is sent.

In your case, you called res.redirect(), which caused the response to become Finished. Then your code threw an error (res.req is null). and since the error happened within your actual function(req, res, next) (not within a callback), Connect was able to catch it and then tried to send a 500 error page. But since the headers were already sent, Node.js’s setHeader threw the error that you saw. Typical error message may look like this:

.............. 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)

Code language: JavaScript (javascript)

HTTP uses a cycle that requires one response per request. When the client sends a request (e.g. POST or GET) the server should only send one response back to it.

“Can’t set headers after they are sent to the client” error may occur due to one of the following reasons:

  • The source code instructs compiler to send multiple responses to the client. Or multiple res functions were called while processing the same request.
  • Sometimes it happens due to asynchronous behavior of Node.js.
  • Sometimes a process sends a response to the client in the event loop, and once it finishes execution, response will be sent again.

Check for duplicate function calls

The Error: Can’t set headers after they are sent. error message usually happens when you send several responses for one request. In order to avoid it, make sure the following functions are called only once per request:

  • res.json()
  • res.send()
  • res.redirect()
  • res.render()
  • ………

Above are the most common response methods that you should check, you can see a comprehensive list of them in https://nodejs.org/docs/latest/api/http.html#http_class_http_serverresponse.

Check for problematic middleware

When you add middleware to connect or express (which is built on connect) using the app.use method, you’re appending items to Server.prototype.stack in connect. When the server gets a request, it iterates over the stack, calling the (request, response, next) method.

If in one of the middleware items writes to the response body or headers, but doesn’t call response.end() and right after that you call next(), “Can’t set headers after they are sent to the client” error may be thrown because response.headerSent is true while there are nothing in the stack anymore.

Below is an example of a good middleware :

// middleware that does not modify the response body var doesNotModifyBody = function(request, response, next) { request.params = { a: "b" }; // calls next because it hasn't modified the header next(); }; // middleware that modify the response body var doesModifyBody = function(request, response, next) { response.setHeader("Content-Type", "text/html"); response.write("<p>Hello World</p>"); response.end(); // doesn't call next() }; app.use(doesNotModifyBody); app.use(doesModifyBody);

Code language: PHP (php)

Redirect without return

One of the common mistake when people make redirects in Express is that they often forget the return statement when calling res.redirect().

// Faulty code auth.annonymousOnly = function(req, res, next) { if (req.user) res.redirect('/'); //ERROR OCCURS HERE next(); };

Code language: JavaScript (javascript)

What you need to do is actually return res.redirect() instead of simply calling it. You may also remove next()

if (req.user) return res.redirect('/');

Code language: JavaScript (javascript)

Faulty conditionals in the code

If your code returns the response based on multiple conditionals, there is a chance that multiple conditions are met, hence multiple responses are sent to the client. See the faulty pseudo-code block below to understand what I mean.

if(someCondition) { await () => { } } await () => { }

Code language: JavaScript (javascript)

Or, with multiple if statements :

if(condition A) { res.render('Profile', {client:client_}); } if (condition B){ res.render('Profile', {client:client_}); } }

Code language: JavaScript (javascript)

Inspect your code carefully, and pay attention to if-else blocks. Better yet, try to return responses when you can (statements after return won’t be executed) to avoid Can’t set headers after they are sent to the client error.

We hope that the article helped you successfully debugged “Can’t set headers after they are sent to the client” error in Express.js, as well as avoid encountering it in the future.

We’ve also written a few other guides for fixing common JavaScript errors, such as How to fix “nodemon: command not found” and npm: command not found . If you have any suggestion, please feel free to leave a comment below.

The Node.js error “Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client” happens when you already sent an HTTP response but then try to send another one. This can be fixed by making sure you’re only sending one response.

So, have a tendency to repeat yourself, huh? No worries! Usually this error is caused by a simple mistake, like a misplaced if statement instead of an else if.

Let’s take a look at a simple NodeJS server application that reproduces this error. There’s lots of ways to spin up a Node server, but the easiest (though not necessarily most common) way is to just use the built-in http module.

Below, we’re going to do just that. We’ll create a simple HTTP server using the built-in http module, set up a couple “routes” (though, they’re not technically called that here) and see what happens.

const http = require('http');
const hostname = '0.0.0.0';
const port = 8000;
const my_server = http.createServer((req, res) => {
    let url = req.url
    if (url == "/") {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/html');
        res.end('<h1>Sup lol</h1>');
    } else if (url == "/about") {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('This is the about page');
    }
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html');
    res.end('<h1>Welcome to my site!</h1>');
});
my_server.listen(port, hostname);

In the above example, we created an HTTP server running on port 8000, on the host “0.0.0.0” – this means we’re listening on all interfaces, which is necessary if you want to reach your NodeJS server from another computer on your network. Then, we created a couple “routes”:

  • / – the root route, also known as the “home page”. This is what comes up when you browse to “http://<your server’s ip>:8000”.
  • /about – a plain-text page with the words “This is the about page” on it.

Then, at the bottom, we have a problem. We’ve created what looks like it should have been another route, but we didn’t enclose it in another else if block. That’s no bueno! What we’re effectively doing is trying to serve up another 200 response and content with every single request made to our web server, even if one had already been sent.

Below is the error message we get when we do this:

_http_outgoing.js:530
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:530:11)
    at Server.<anonymous> (/home/user/main.js:21:9)
    at Server.emit (events.js:314:20)
    at parserOnIncoming (_http_server.js:779:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:122:17) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

Look familiar? It should. It’s probably the reason you’re here.

What this error is telling us is, as you might guess, we tried to respond to the same request twice. While the error is specifically saying that it can’t set headers after they’re already sent to the client, it’s still caused by the same issue of responding twice.

Fixing this is pretty easy…

Make sure you are only sending one request

Don’t repeat yourself! Make sure your server is only responding to a request once. Our example is pretty trivial, so it’ll be equally trivial to fix. Real world server applications might have their duplicate response buried under several layers of abstraction, making your job a little harder. You might even need to bust out the Node debugger.

But we don’t need to go that far. All we’re going to do is wrap that last response in an else if block:

const http = require('http');
const hostname = '0.0.0.0';
const port = 8000;
const my_server = http.createServer((req, res) => {
    let url = req.url
    if (url == "/") {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/html');
        res.end('<h1>Sup lol</h1>');
    } else if (url == "/about") {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('This is the about page');
    } else if (url == "/welcome") {
        res.statusCode = 202;
        res.setHeader('Content-Type', 'text/html');
        res.end('<h1>Welcome to my site!</h1>');
    }
});
my_server.listen(port, hostname);

That’s all there is to it! But, I should really tell you, nobody makes real web servers this way. Or, at least, they probably shouldn’t (unless they really know what they’re doing). There’s a much easier way that basically everyone is using…

ExpressJS has become sort of the de-facto standard for Node server-side web apps. It’s a very easy and convenient way to create an app to serve up single page web apps (SPAs) and their associated APIs.

How to install express

Installing express is super easy as well. It can be done with the Node Package Manager, npm, which comes with most OS’s NodeJS installation packages:

This will install express locally for your project, i.e. in the node_modules directory. If you don’t already have a package.json set up for your app, this will create one for you.

Optionally, you can also install express globally with:

But this isn’t recommended by me personally – I like to keep my packages local. The more you junk up your global installs, the harder it’s going to be to debug when your app inevitably has issues with which version of the packages you have installed.

Express app example

Now that we’ve got express installed, let’s take a look at how we could re-do our above example:

const express = require('express');
const my_server = express();
const port = 8000;
my_server.get("/", (req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html');
    res.end('<h1>Sup lol</h1>');
});
my_server.get("/about", (req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('This is the about page');
});
my_server.get("/welcome", (req, res) => {
    res.statusCode = 202;
    res.setHeader('Content-Type', 'text/html');
    res.end('<h1>Welcome to my site!</h1>');
});
my_server.listen(port);

As you can see, it’s much harder to accidentally send two responses for a single request. Express JS forces you to separate out your “routes” (not sure what they call them, but this is the Ruby on Rails and Laravel terminology). It’s also less code overall to set up since it handles a lot of things for you behind the scenes.

Don’t reinvent the wheel by using the old built-in http module, though it is good to do one for practice just so you know how it all works. After all, these fancy frameworks just use that module under the hood anyway. Usually.

Work smarter not harder!

Conclusion

We covered what causes “Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client” as well as a couple different ways to fix it. In summary, make sure you’re not trying to do any funny business after your response has been sent to the client. There really shouldn’t be anything left for you to do at that point aside from any side-effects or cleanup that you might need. Secondly, just use a framework like Express JS. They make it much harder for you to make this mistake.

That’s all for now, good luck and happy coding!

When using express and Node.JS, we will sometimes get this error:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:277:15)
    at ServerResponse.setHeader (node:_http_outgoing:563:11)
    at ServerResponse.header (/node_modules/express/lib/response.js:771:10)
    at file:///link/to/file/app.js:309:13 {
    code: 'ERR_HTTP_HEADERS_SENT'
}

This is quite a confusing error if you aren’t familiar with HTTP headers. This error arises when you send more than 1 responses to the user or client. That means the receiver is getting two responses, when it should only be getting one. To solve this, make sure you are only sending one response.

How to solve the ERR_HTTP_HEADERS_SENT error

This can often be caused when you send a response to the client, and an asychronous piece of code then sends a second response after the first. Look in your code, you may be accidentally using res.send twice. For example, the below will cause the error:

app.get('/app', async function(req, res) {
    /* Don't do this! Remove one of the res.send functions to remove the error */
    await User.find({username: req.headers.username}, function(err, items) {
        res.send('User');
    })
    res.send('Hello');
})

Note: other res functions, such as res.redirect will cause the same issue, i.e. the below code is also wrong:

app.get('/app', function(req, res) {
    /* Don't do this! Remove one of these functions to remove the error */    
    await User.find({username: req.headers.username}, function(err, items) {
        res.redirect('/app/login');    
    })
    res.send('Hello');
})

Your code should instead look like this, with only one res function:

app.get('/app', function(req, res) {
    res.redirect('/app/login');
})

Preventing multiple headers from being sent

If you want to prevent multiple headers being sent with certainty in Express and Node.JS, use res.headersSent. If it’s set to true, then the headers have already been sent.

For example, the following code will work as res.headerSent prevents headers from being re-sent:

app.get('/app', function(req, res) {
    res.send('Hello');
    
    // Will not send, as we have already sent once.
    // Prevents error.
    if(res.headersSent !== true) {
        res.send('Hello');
    }
})

Last Updated 1620568390116

The primary cause of the error, «Error: Cannot set headers after they are sent to client» is sending multiple HTTP responses per request. The error mainly occurs when you run any of the five response methods after another in a middleware or route function: json(), send(), sendStatus(), redirect(), and render().

This tutorial shows multiple ways to produce and solve the error «Error: Cannot set headers after they are sent to client

Before that, it would be best to understand the workings of the http and express modules. What is more?

Find out below.

Understand the http module

Since the origin of the error «Error: Cannot set headers after they are sent to client» is disobeying a critical HTTP rule, it is important to understand how the http module works in Node.js.

HTTP enables transferring information between the client (browser) and a web server. It comes with methods like GET and POST, which determine how information is transferred. Other metadata are content type and length. The metadata is often referred to as headers.

ALSO READ: JavaScript localStorage Event Handler Example [SOLVED]

The client makes a request. The request gets wrapped in the request object and sent to the server. The server handles the request and sends feedback in the response object.

Node.js presents you with the http module to handle the request and response objects. First, we import the built-in module, create a web server and listen for a request event.

import http from 'http'

const app = http.createServer()

app.on('request', (req, res) => {
    if (req.url === '/') {
        res.writeHead(200, {'content-type': 'text/html'})
        res.write('<h2>Home Page</h2>')
        res.end()
    }
})

app.listen(3000)

The on() method has a callback function that handles request and response objects. For example, we can check the route req.url === '/' making the request before sending the response headers and body. The end() method terminates the response. That concludes one HTTP cycle.

As you can see from the above example, writing useful code with the raw http module could be hectic. That is where express comes to the rescue.

Why express produces the error, “Error: Cannot set headers after they are sent to client

express is a wrapper around the http module. It simplifies creating routes and custom middleware. Middleware is a function that sits between the request and response objects and controls the communication.

express infers middleware type depending on the number of supplied parameters. For example, a route middleware accepts a callback with the request and response parameters. A custom middleware often receives the request, response, and next parameters. Lastly, an error handler mostly accepts error, request, response, and next parameters.

ALSO READ: JavaScript Each vs In [With Examples]

The client sends a request. express receives and handles the request through the request parameter. After handling the request, it sends feedback through the response object handler. That completes one HTTP cycle.

express terminates an HTTP cycle by sending one of these methods: json(), send(), sendStatus(), redirect(), or render().

json() sends JSON to the client. send() mainly sends strings, buffers, or objects. sendStatus() sets the response status code and sends its string representation. For instance, a 200 status code equates to OK.

redirect() redirects the user to a URL. render() sends a file, mostly referred to as a view, like index.html and index.ejs.

Sending two or more response methods in the same control flow and middleware invokes the error, «Error: Cannot set headers after they are sent to client

Here is a practical example.

Lab environment setup

Launch your terminal. Create the project directory and cd into it before initializing npm and installing the application dependencies.

mkdir httpHeaders && cd httpHeaders
npm init -y
npm i express nodemon ejs express-ejs-layouts
code .

express is the web server; nodemon, restarts the server when you modify the script file; ejs, templating engine; express-ejs-layouts, creates ejs layouts. We then open the project in Visual Studio Code.

Cannot set headers after they are sent to client [SOLVED]

Since we will be using ECMAScript modules, it would help to specify the module type "type": "module" before modifying the test script to use nodemon.

package.json

{
  "name": "httpheaders",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "nodemon index"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ejs": "^3.1.8",
    "express": "^4.18.2",
    "express-ejs-layouts": "^2.5.1",
    "nodemon": "^2.0.20"
  }
}

Now let’s invoke and solve the error, «Error: Cannot set headers after they are sent to client.»

ALSO READ: Objects are not valid as a react child [SOLVED]

Practical examples

Assume we want to send the home page when a request is made through the slash / route. And redirect the user to the home page on making a request at the /about page.

views/layout.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <%- body %>
</body>
</html>

views/index.ejs

<h2>Home Page</h2>

index.js

import express from 'express'
import layouts from 'express-ejs-layouts'

const app = express()

app.set('view engine', 'ejs')
app.use(layouts)

app.get('/', (req, res) => {
    res.render('index')
})

app.get('/about', (req, res) => {
    res.redirect('/')
})

app.listen(3000)

before the Error: Cannot set headers after they are sent to client

In the process, we (accidentally) send multiple responses per request.

Example~1: sendStatus() and json()

app.get('/about', (req, res) => {
    // res.redirect('/')
    res.sendStatus(200).json({ message: 'Redirecting to the home page.'})
})

res.sendStatus(200) ends the HTTP cycle with the OK message. The JSON from json({ message: 'Redirecting to the home page.'}) is treated as another send response.

Cannot set headers after they are sent to client [SOLVED]

The solution here is to use res.status(200) instead of res.sendStatus(200).

app.get('/about', (req, res) => {
    // res.redirect('/')
    // res.sendStatus(200).json({ message: 'Redirecting to the home page.'})
    res.status(200).json({ message: 'Redirecting to the home page.'})
})

Example~2: redirect() and json()

If we uncomment the redirect method, we get another error. Reason?

app.get('/about', (req, res) => {
    res.redirect('/')
    res.status(200).json({ message: 'Redirecting to the home page.'})
})

res.redirect('/') ends the HTTP cycle. The next nested response methods are meaningless to an already closed header.

Cannot set headers after they are sent to client [SOLVED]

ALSO READ: How to round down a number JavaScript [SOLVED]

Conclusion

The key takeaway from this tutorial is that nesting or running multiple response functions per request in a scope produces the error:  Cannot set headers after they are sent to client. You can solve the error as explained in the tutorial.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Cannot resolve symbol string java ошибка
  • Cannot resolve symbol java intellij idea ошибка