code throws error, write after end but why

So i made a small api to start up minecraft servers in screen, which works fine. But now, everytime i start or stop the server, the api crashes somehow because the http server wrote after an end, i cant find anything that ended the server.

I cant seem to find where it ends, its very weird.

I am new to http servers, api’s and this stuff so it may be just my dumb fault.

//@author WizzerStudios on Github
//CC 2021 
//Allowed:
//:: Editing
//Disallowed
//:: Redistributing
//:: Claiming as yours 
 
//Importing stuff
var http = require('http');
const { exec } = require("child_process");
var url = require('url');
var https = require('https');
const fs = require('fs');
 
//Console log
console.log("Wizzer API booted.")
 
//Create API / HTTP Server
http.createServer(function (req, res) {
  var q = url.parse(req.url, true).query;
 
  //Check if password is correctly given.
  if(q.password == "Password"){
    //Switch to the action.
    switch(q.action){
      //If action is undefined:
      case undefined:
        res.end("Action not given.");
        break;
      //Get Logs is coming soon.
      case "getlogs":
        if(q.sname == undefined) res.end("No server name given.");
        try {
          const data = fs.readFileSync('serverfiles/' + q.sname + '/logs/latest.log', 'utf8');
          res.end(data);
        } catch (err) {
          console.error(err)
          res.end("Error occured! Server does not exist or isn't available.");    
        }
        break;
      //Start the server using the bash screen command.
      case "stop":
       //If no server name is given, end the connection.
       if(q.sname == undefined) res.end("Server name not specified.");
       //If server exists, run the screen command.
       if (fs.existsSync('./servers/' + q.sname + '.json')) {
         //Check if a screen session with the same name is already running.
         exec('screen -S ' + q.sname + ' -Q select . ; echo $?',
         (error, stdout, stderror) => {
         if (error) {
           console.error("Error: ", error);
           return;
         }
         var out = stdout;
         if(out.includes('0')){
          exec('screen -p 0 -S minecraft-server -X eval `stuff "say TEST MESSAGE..."5`', (error, stdout, stderror) => {
            res.end("Server stopped!"); //It says it stopped and crashes here !!!
          });
         } else {
           res.end('Server already stopped!');
           return;
         }});
       } else {
         res.end("Server does not exist!");
         return;
       }
       break;
      case "start":
        //If no server name is given, end the connection.
        if(q.sname == undefined) res.end("Server name not specified.");
        //If server exists, run the screen command.
        if (fs.existsSync('./servers/' + q.sname + '.json')) {
          //Check if a screen session with the same name is already running.
          exec('screen -S ' + q.sname + ' -Q select . ; echo $?',
          (error, stdout, stderror) => {
          if (error) {
            console.error("Error: ", error);
            return;
          }
          var out = stdout;
          if(out.includes('1')){
            exec('screen -S ' + q.sname + ' -dm bash /home/mcserver/api/serverfiles/' + q.sname + '/start.sh', (error, stdout, stderror) => {
              res.end("Server started!"); // Here it says it already stopped!
            });
          } else {
            res.end('Server already started!');
            return;
          }});
        } else {
          res.end("Server does not exist!");
          return;
        }
        break;
      //Create server action.
      case "createServer":
        //If no game is given, end connection.
        if(q.game == undefined) res.end("Game not given");
        //Switch to the game chosen.
        switch(q.game){
          //Minecraft
          case "minecraft":
            if(q.sname == undefined) res.end("Server name not given."); // No server name given, end connection.
            if(q.port == undefined) res.end("Port not given."); // No port given, end connection.
            if(q.ram == undefined) res.end("Please give ram in gigabytes."); // No ram given, end connection.
            if(q.software == undefined) res.end("Server software not given."); // Server software not given, end connection.
            if(q.version == undefined) res.end("Server version not given."); // Version not given, end connection.
            //Check if server already exists:
            var path = './servers/' + q.sname + '.json';
            if (fs.existsSync(path)) {
              res.end("Server Exists.");
              return;
            }
            ram = Number(q.ram);
            ram *= 1024;
            let server = { 
              name: q.sname,
              port: q.port, 
              game: 'Minecraft',
              ram: Number(ram),
              software: q.software,
              version: q.version
            };
            let data = JSON.stringify(server, null, 2);
            fs.mkdir('./serverfiles/' + q.sname, (err) => {
                if (err) {
                    throw err;
                    res.end(err)
                }
            });
            fs.writeFile('./serverfiles/' + q.sname + '/eula.txt', 'eula=true', function (err) {
              if (err) res.end(err);
              if(err) console.log(err);
            });
            fs.writeFile('./serverfiles/' + q.sname + '/start.sh', '#!/bin/bashnjava -Xmx' + Number(ram) + 'M ' + '-Xms' + Number(ram) + 'M -jar /home/mcserver/api/serverfiles/' + q.sname + '/server.jar', function (err) {
              if (err) res.end(err);
              if(err) console.log(err);
            });
            exec('chmod +x ./serverfiles/' + q.sname + '/start.sh');
            fs.writeFile('./serverfiles/' + q.sname + '/server.properties', 'port=' + q.port, function (err) {
              if (err) res.end(err);
              if(err) console.log(err);
            });
            try{
                https.get("https://serverjars.com/api/fetchJar/" + q.software + "/" + q.version, function(response) { response.pipe(fs.createWriteStream("serverfiles/" + q.sname + '/server.jar'))});
            } catch(err){
                res.end("Failed!")
                console.log(err)
            }
            fs.writeFile("servers/" + q.sname + ".json", data, (err) => {});
            res.write("Server Software: " + q.software);
            res.write("nRam: " + Number(ram));
            res.write("nServer name: " + q.sname);
            res.write("nGame: Minecraft");
            res.write("nPort: " + q.port);
            res.end("nVersion " + q.version);
        }
    }
    //if(req.url == "/?password=Password&?action=create"){
    //  res.write("game not given")
    //} else if(req.url == "/?password=Password&?action=create&game"){
    //  res.write("Authenticated!")
    //}
  //} else {
    //res.write("WRONG PASSWORD!")
  }
  res.end(); //end the response
}).listen(8080); //the server object listens on port 808
events.js:174
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at write_ (_http_outgoing.js:572:17)
    at ServerResponse.write (_http_outgoing.js:567:10)
    at exec (/home/mcserver/api/index.js:86:21)
    at ChildProcess.exithandler (child_process.js:285:7)
    at ChildProcess.emit (events.js:198:13)
    at maybeClose (internal/child_process.js:982:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
Emitted 'error' event at:
    at writeAfterEndNT (_http_outgoing.js:634:7)
    at process._tickCallback (internal/process/next_tick.js:63:19)
``` is the error.

I do know that i'm writing after the end, but where did it end?

Also, changing res.write to res.end doesn't crash my code, but it doesn't give anything in my browser.

Answer

Take out the following line:

  res.end(); //end the response <-----------------
}).listen(8080); //the server object listens on port 8080

You are calling “res.end()” after already calling it inside the function

            res.end("nVersion " + q.version); // In createServer

calls it then it drops out the switch statements and executes the above res.end() again

Source: stackoverflow
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .