0

I am creating an application and when I try to upload an image it gives this error in the console: (node:23) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. How can I solve this?

My fetch:

let formData = new FormData();
formData.append('arquivo', document.querySelector('input[name="arquivo"]').files[0])
formData.append('candy', candy)
formData.append('theme', document.getElementById('candytheme').value)

fetch('https://nodemae.herokuapp.com/candy', { method: 'post', headers: {'x-auth-token': window.sessionStorage.getItem('token') }, body: formData}).then

My server side:

async store(req, res) {
    let candy= req.body.candy;
    let name= uniqid(doce+'-')+'.jpg';
    let route= `/img/${doce}/`;
    let theme= req.body.theme;
    let sampleFile = req.files.arquivo;
    sampleFile.mv(`./public${route}${name}`, function(err){
        if (err) {
            return res.send(err)
        }
    });
    const candy = await Candy.create({
        name: name,
        candy: candy,
        route: route,
        theme: theme
    });

    return res.json(candy);
},

The return res.json (candy); returns this:{"errno":-2,"code":"ENOENT","syscall":"open","path":"./public/img/paomel/paomel-q6zynjrg8w45y.jpg"}

enter image description here

Henrique Ramos
  • 714
  • 8
  • 25
  • what `Candy.create` looks like? – Vadi Jan 28 '19 at 11:33
  • @Vadi Candy.create is just inserting into the database the path and type of the candy. it inserts into the database but the image is not being placed in public / img / candy / candyname.jpg – Henrique Ramos Jan 28 '19 at 11:36
  • I think if you have an error it doesn't get inside this statement `if (err) { return res.send(err) }`. This is why it pass to the final `return res.json(candy);` . Try to use log to make sure it gets inside it `if (err) { console.log('about to send error '); return res.send(err) }` – Vadi Jan 28 '19 at 11:42
  • @Vadi I'm starting to think that the error is in this (err) but I can not solve it – Henrique Ramos Jan 28 '19 at 12:07
  • you have an error related `sampleFile`, but you also have an error `Cannot set headers after they are sen...`, which tells that you do not get inside `if (err) { return res.send(err) }`. I don't know what `samplFile.mv` does, but `"ENOENT","syscall":"open","path":"./public/img/paomel/paomel-q6zynjrg8w45y.jpg` means that there is no file `./public/img/paomel/paomel-q6zynjrg8w45y.jpg` – Vadi Jan 28 '19 at 12:20
  • sampleFile.mv is just a function of the express-fileupload package – Henrique Ramos Jan 28 '19 at 12:22
  • Possible duplicate of [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) – ponury-kostek Jan 28 '19 at 12:58

2 Answers2

0

You are getting this error because of this callback function

 sampleFile.mv(`./public${caminho}${nome}`, function(err){
    if (err) {
        return res.send(err)
    }
});

Your code sends response back from res.json(candy); while running synchronously, but when asynchronous callback is fired for, You are getting err and ` return res.send(err)

Solution

try this code

async store(req, res)
{
try {
    let doce = req.body.doce;
    let nome = uniqid(doce+'-')+'.jpg';
    let caminho = `/img/${doce}/`;
    let tema = req.body.tema;
    let sampleFile = req.files.arquivo;
    await sampleFile.mv(`./public${caminho}${nome}`)
    const candy = await Candy.create({
            nome: nome,
            doce: doce,
            caminho: caminho,
            tema: tema
        });

        return res.json(candy);
    });
}catch (err) {
    return res.send(err)
}}
Afraz Ahmad
  • 386
  • 1
  • 5
  • 20
0

An error occures while executing sampleFile. Other parts of code need to wait until sampleFile has finished. So you have two errors: "errno":-2,"code":"ENOENT","syscall":"open","path":"./public/img/paomel/paomel-q6zynjrg8w45y.jpg" (because it cannot find a file) and the second one Cannot set headers after they are sent to the client... (because your code doesn't handle error and follows to the final return res.json(candy); Try:

async store(req, res) {
  let candy= req.body.candy;
  let name= uniqid(doce+'-')+'.jpg';
  let route= `/img/${doce}/`;
  let theme= req.body.theme;
  let sampleFile = req.files.arquivo;
  sampleFile.mv(`./public${route}${name}`, async function(err) {
      if (err) {
        res.send(err)
      } else {
        const candy = await Candy.create({
          name: name,
          candy: candy,
          route: route,
          theme: theme
        });

        res.json(candy);
     }
   });
}

You can also use then, without async and await:

store(req, res) {
  let candy= req.body.candy;
  let name= uniqid(doce+'-')+'.jpg';
  let route= `/img/${doce}/`;
  let theme= req.body.theme;
  let sampleFile = req.files.arquivo;
  sampleFile.mv(`./public${route}${name}`, function(err) {
      if (err) {
        res.send(err)
      } else {

        Candy.create({
          name: name,
          candy: candy,
          route: route,
          theme: theme
        })
        .then(function(candy) {
          res.json(candy);
        })
        .catch(function(err) {
          console.log(err);
        });  
     }
   });
}

Try to use absolute path here /public${route}${name} for file uploading, because fileupload package doesn't use relative paths.

Vadi
  • 3,279
  • 2
  • 13
  • 30