Home > Enterprise >  solution of error of cannot set headers after they are sent to the client though i am returning resp
solution of error of cannot set headers after they are sent to the client though i am returning resp

Time:01-05

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;
            }
        });

CodePudding user response:

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;
            }
//...           

CodePudding user response:

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

  •  Tags:  
  • Related