1

I am working on expressJS and this is my code in controller:

inside file readstream i had this condition check and whenever this met i no-longer want to read file because it means that it is not in correct data format:

if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
              return res.status(500).send(" file format not supported");
              } 

even though I am returning this return statement I am getting

error of cannot set headers after they are sent to the client though I am returning response

SOLUTION AND EXPLANATION

I found the solution because all over the internet the solution people suggest is to use return.

I am writing this because if someone comes again here for the same problem, he/she can understand the problem.

That error basically means that there is already status and message sent to the response like with res.status(500).send(error.message)

if your code does not end here and traverse further and encounter another return.status().send() then there comes an error because the second response object status assignment is not possible because it is already assigned.

in most of the case if we return the code execution stops but in case of event handler where there is another event triggered while returning from the function and if that event handler has response sending operation then return can't save you like in this code:

const rl = readLine.createInterface({
            input: fs.createReadStream(req.file.path)
        });

        rl.on("line", line => {
            const cols = line.split(",");
            const waveType = cols[0];
            const startTime = cols[1];
            const endTime = cols[2];
            const tags = cols.slice(3);

            //just to make sure csv has valid data list
            if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
                return res.status(500).send("File not supported");
            } 

and down the code there is

 rl.on("close", () => {

            if (notSupportedFlag) {
                notSupportedFlag = false
                return res.status(500).send("File data is not supported format");
            } else {
                let heartRate = Math.floor(frequencyCollector.sumOfFrequency / frequencyCollector.cycleCount);
                results.meanFrequency = heartRate;
                results.maxFrequency.time += Number(req.body.time);
                results.minFrequency.time += Number(req.body.time);
                res.status(200).json(results);
                return;
            }
        });

return can't save you here because when you return that response close event will be called so only thing that we can do here is to perform one response send.

Like the answer posted by @tryanner but here I will add one more thing:

// set this variable before reading with false as default/start value
    let notSupportedFlag= false;

inside readline.on ("line", line =>{

if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
                notSupportedFlag = true;
                rl.close();
                rl.removeAllListeners();
            }

then inside close operation we will do this:

rl.on("close", () => {

            if (notSupportedFlag) {
                notSupportedFlag = false
                return res.status(500).send("File data is not supported format");
            } else {
                //do whatever you do in case of successful read
                return;
            }
        });
Pravin Poudel
  • 1,433
  • 3
  • 16
  • 38
  • 1
    This is a dup of https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client?rq=1. Debug by console logging everyplace you set res.status(). Look at the logs and you'll see you're calling res.status().send() somewhere, then calling it again on the same request. – danh Jan 04 '22 at 07:11
  • Does this answer your question? [Error: Can't set headers after they are sent to the client](https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client) – danh Jan 04 '22 at 07:11
  • no i couldnt get any help from it rather i learnt why there is this error but couldn't find why in my code !!! this error mean that after sending response with status, my code is again trying to set res.status() but i don't see where it is happening !!! – Pravin Poudel Jan 04 '22 at 07:21
  • @danh what i found from console.log() is that even if there is error and i am calling return res.status(500).send("File data entry is not in supported format") it is still going into .on ("close", ()=>{}) where i am returning for the case of everything went right !!! – Pravin Poudel Jan 04 '22 at 07:28
  • @danh is it correct way to check custom error and it seems after that the close event is called !!! – Pravin Poudel Jan 04 '22 at 07:47
  • that is reason of error !! how to handle the error – Pravin Poudel Jan 04 '22 at 07:47

2 Answers2

1

The problem is that the stream is still sending the response multiple times from line event, every time it reads a line.

So, you need to end the stream.

However, it doesn't seem to work like that, because:

Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the InterfaceConstructor instance.

https://nodejs.org/api/readline.html#rlclose

which means the line will emit again, and cause the same error, so you cannot return response from the line event, but somewhere else.

You need to rewrite the code accordingly.

For example, add the variable to track the error manually, close the stream in line, and then check for error there, and return error, if any, success if not.

// track error
let error;

// setup reader to close it later
const reader = readLine.createInterface({

//...

if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
    error = 'File data entry is not in supported format';
    // close
    reader.close()
    return;
}

//...

}).on("close", () => {
            if (error) {
                res.status(500).send(error);
                error = '';
                return;
            }
//...           
traynor
  • 5,490
  • 3
  • 13
  • 23
0

I think in your readLine handlers when you return in its functions, it just return from those function. try with a return in behind of readLine.createInterface

Ali Fakoor
  • 82
  • 2