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


Written By - Steve Alila
Advertisement

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.

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.

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

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

 

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]

 

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.

 

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment