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 }).
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: How to check if string is number in JavaScript? [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 Destructuring [In-Depth Tutorial]
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] Cannot set headers after they are sent to client [SOLVED]](https://www.golinuxcloud.com/wp-content/uploads/lab-setup-2-18.jpg)
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: JavaScript Math.sign() Examples [In-Depth Tutorial]
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)
![Cannot set headers after they are sent to client [SOLVED] before the Error: Cannot set headers after they are sent to client](https://www.golinuxcloud.com/wp-content/uploads/correct-implementation.jpg)
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] Cannot set headers after they are sent to client [SOLVED]](https://www.golinuxcloud.com/wp-content/uploads/the-error.jpg)
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.
ALSO READ: Implementing NodeJS CMS with express and MongoDB
![Cannot set headers after they are sent to client [SOLVED] Cannot set headers after they are sent to client [SOLVED]](https://www.golinuxcloud.com/wp-content/uploads/another-error.jpg)
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.
Chances are as a NodeJS developer you’ve encountered this runtime error:
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
You must have written the perfect code and expect a flawless code excution (i wish 😆), but here is this runtime error shattering your expectations and definitely keeping you from moving on to other concerns of your project. Now you begin to ask yourself why you even choose this career path or even why you picked up node in the first place.
SPOILER ALERT: I have run into this runtime error couple times while building restful API’s and this is an effort to document what i learnt about this error, shorten your debugging time, help you understand why this error is thrown and finally how best handle it.
Uncovering the mystry
Error [ERR_HTTP_HEADERS_SENT] is an interesting error that is fired up when a server tries to send more than one response to a client. What this means is that for a given client request the server previously sent a response (either a success responsei with the resource requested or error response for a bad request) back to the client and now is unexpectedly trying to send another response 
[Case Study] talk is cheap
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.post('/test', (req, res) => {
if (!req.body.name) {
res.status(400).json({
status: 'error',
error: 'req body cannot be empty',
});
}
res.status(200).json({
status: 'succes',
data: req.body,
})
});
app.listen(4000, () => {
console.log('Server live');
});
Enter fullscreen mode
Exit fullscreen mode
This case study is based on a simple POST request to a /test route using the express framework.
By design the server should send back a 400(Bad request) JSON response to the client if a request does not have a body(req.body) added to the request to ther server from the client (handled with the javascript if statement) and lastly if the request comes with a body a 200(OK) JSON respresention of the request body is sent back to the client as response . The expectation is that the request handler should do what we’ve programmed it to do (return response to the client). The request handler(the anononymous function that takes the req & res arguements) is simply a javascript function and this means that the javascript engine(v8 in nodes case) keeps executing the code beyond the if statement when there is no explicit instruction for it to exit the function.
Looking at the code logic you’d aggree that the request handler function has no explicit command for exiting the function in a situation a reqest body is not found and the error response is sent back to the client, therefore after the if statement condition has being resolved the server tries to send another response to the client
and this is where the error kicks in.
The request handler function already sent a response to the client using the res.json() method which automatically sets the response header(every response to the client should contain headers) for the response(in this case theContent-Type to application/json). Node picks up this atrocity and our server crashes because express under the hood is attempting to set the response header for this second response, hence the error message:
Cannot set headers after they are sent to the client
Fixing the error
The simple fix for this error is to add javascript return statement to the response being sent from the if conditional to ensure that the request handler function exits(terminate) excuting code with the function once a response has being sent to the client.
The description for the return statement on MDN states
When a return statement is used in a function body, the execution of the function is stopped. If specified, a given value is returned to the function caller.
With this in mind, our request handler function should be modified to include a return statement like so:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.post('/test', (req, res) => {
if (!req.body.name) {
return res.status(400).json({
status: 'error',
error: 'req body cannot be empty',
});
}
res.status(200).json({
status: 'succes',
data: req.body,
})
});
app.listen(4000, () => {
console.log('Server live');
});
Enter fullscreen mode
Exit fullscreen mode
When a client makes a server request to this endpoint with or without a request body to the server request, the server sends the correct response and stop the function execution as necessary.
You’d be tempted to ask why the last server response has no return statement sending it to the client?, well in this case there is really no need to return it since there is no code further down the function to be excuted so it means the the request handler stops excuting since it has comee to the end of the road.
The point is that Javascript return statement exits the request handler function (to prevent further code execution) and sends a response object back to the client.
Hopefully, you now have a better understanding of why this error message is fired and how to resolve it 😄, and i hope by documenting this error and it’s fix I shorten your debugging time and helped you understand why this error is fired.
I have a GitHub repository for the failing code and passing code, you can clone and play with the code by trying out some other use case (hopefully can send a PR for your use case).
Thanks for reading
Trouble
Your Express.js server is throwing an ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client and you have a useless stack trace to work
from like the following:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:467:11)
at ServerResponse.header (/usr/src/app/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/usr/src/app/node_modules/express/lib/response.js:170:12)
at done (/usr/src/app/node_modules/express/lib/response.js:1008:10)
at render_file (/usr/src/app/node_modules/hbs/lib/hbs.js:49:14)
at ReadFileContext.callback (/usr/src/app/node_modules/hbs/lib/hbs.js:168:16)
at FSReqCallback.readFileAfterOpen [as oncomplete] (fs.js:232:13)
Why the heck do I get this?
As the cause of this issue is extremely well explained in «Understanding Node
Error ERR_HTTP_HEADERS_SENT» by Prosper
Opara
I let you get the insights there.
I would just add to the article that the lack of using the return keyword when
calling the Express next() function may also cause the ERR_HTTP_HEADERS_SENT
issue.
Solution
By browsing the Express.js git
repository I came across this issue that
provides a very neat code
snippet that improves the
stack trace to identify the line responsible for the issue.
The code snippet consists of a middleware that monkey patches the res.render
and res.send Express.js functions in order to prevent the application from
crashing and improve the logged stack trace.
Here is the snippet:
app.use((req, res, next) => {
const render = res.render;
const send = res.send;
res.render = function renderWrapper(...args) {
Error.captureStackTrace(this);
return render.apply(this, args);
};
res.send = function sendWrapper(...args) {
try {
send.apply(this, args);
} catch (err) {
console.error(`Error in res.send | ${err.code} | ${err.message} | ${res.stack}`);
}
};
next();
});
If you plug this onto your Express.js application you will get a much more
useful stack trace like below:
Error in res.send | ERR_HTTP_HEADERS_SENT | Cannot set headers after they are sent to the client | Error
at ServerResponse.renderWrapper [as render] (/usr/src/app/app/server.js:289:15)
at index (/usr/src/app/app/controllers/home-controller.js:88:21)
at processTicksAndRejections (internal/process/task_queues.js:89:5)
In the above stack trace the line responsible for the second render is the
line 88 of the home-controller.js file. Bingo!
All the credit should go to James Starkie a.k.a jstarmx on
Github. James you made my day on this one ☀️.
NOTE: Do not forget to remote the middleware once you are done debugging 😉
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
