19

I'm trying to upload an image (jpg/jpeg/png) from the browser to NodeJS. I have read through several tutorials and many posts on forums but very few seem to have this specific issue.

  • I've made sure to match the name provided to multer (upload.single('upload')) with the formData key (formData.append('upload', selectedFile, selectedFile.name))
  • I tried using headers originally, but later read that I should exclude them.
  • I tried submitting through a <form action="/upload" method="post" enctype="multipart/form-data"> but still got the same error.

I have found this similar question with only one answer which isn't clear Multer gives unexpetcted end of form error and this question Unexpected end of form at Multipart._final which has no answers. Every other question seems to be about an 'Unexpected field' or 'Unexpected end of multipart data' error which - judging from the solutions - is irrelevant here.

Below is my code...

Browser:

<body>
  <input type="file" id="file_uploader" name="upload" />
  <button onclick="uploadImage()" class="btn-default">SUBMIT</button>
  
  <!-- OTHER STUFF -->

</body>
<script>
  let selectedFile;
  let uploadData = new FormData();
    
  const fileInput = document.getElementById('file_uploader');
  fileInput.onchange = () => {
    selectedFile = fileInput.files[0];
    uploadData.append('upload', selectedFile, selectedFile.name);
  }

  function uploadImage(){
    fetch('/upload', {
      method: 'POST',
      body: uploadData
    }) 
    .then((response) => {
      console.log(response);
    })
    .catch((error) => {
      console.error('Error: ', error);
    });
  }
</script>

NodeJS

let express = require('express');
const multer = require('multer');

//multer options
const upload = multer({
  dest: './upload/',
  limits: {
    fileSize: 1000000,
  }
})

const app = express();

app.post('/upload', upload.single('upload'), (req, res) => {
  res.send();
}, (error, req, res, next) => {
  console.log(error.message);
})

exports.app = functions.https.onRequest(app);

...And here is the error log, if it helps:

Error: Unexpected end of form
>      at Multipart._final (C:\Users\p\Downloads\MyInvestmentHub\functions\node_modules\busboy\lib\types\multipart.js:588:17)
>      at callFinal (node:internal/streams/writable:694:27)
>      at prefinish (node:internal/streams/writable:723:7)
>      at finishMaybe (node:internal/streams/writable:733:5)
>      at Multipart.Writable.end (node:internal/streams/writable:631:5)
>      at onend (node:internal/streams/readable:693:10)
>      at processTicksAndRejections (node:internal/process/task_queues:78:11)

I haven't posted many questions as of yet, so I apologise if I'm missing something or the format is off. Let me know and I will make appropriate edits.

Thanks.

Updog
  • 321
  • 1
  • 2
  • 8
  • whats @Updog (see what i did there) anyways, i got this exact same error, in my code i was saying if there was an error, console log the err and it was returning a simplified message, but i removed the console log and it revealed a larger issue, which was a directory direction, i.e. `this directory doesnt exist` make sure that the directory your pointing to actually exists, if it doesnt, make sure you create it. – Austin Howard Jun 11 '22 at 16:06
  • Hey what's up, lol. I've messed around with the directory already and noticed that, if there isn't a directory in the location I specified, it creates one anyway! It's definitely worth having another look at though, since I'm out of options. – Updog Jun 13 '22 at 08:21
  • Hi , are you able to find the solution? I am stuck in the issue for sometime. – pratim Jul 19 '22 at 13:22
  • 1
    @pratim No sorry, I did not. I eventually moved onto other tasks. I will come back to it. I haven't tried the suggestion by SocalWudan yet, it may work. Good luck! report back here if you solve it :D – Updog Jul 20 '22 at 14:13
  • If the user first selects one file, then changes their mind and selects another, `uploadData.append` is executed for both files. Not sure if this is related to your problem, but it's not what you want. Move the `let uploadData = new FormData();` inside the `fileUpload.onchange` function. – Heiko Theißen Jul 23 '22 at 07:19
  • @HeikoTheißen Hi, no it is not related to my problem but I appreciate it anyway. I would not have noticed that. Thanks! – Updog Jul 25 '22 at 08:47

14 Answers14

14

I had this problem using multer with next js api. What worked for me is, I exported a config that sets bodyParser to false like so;

export const config = {
  api: {
    bodyParser: false
  }
}
Luck1609
  • 226
  • 2
  • 6
  • 1
    For Next.js, This is the right answer. – Mahmoud Oct 23 '22 at 20:21
  • 1
    For others, to be clear, this `export` is in the API route file. https://nextjs.org/docs/api-routes/request-helpers Should mark as correct answer. – Corey Gwin Nov 07 '22 at 21:31
  • Could you have a look at this please? I'm using bodyParser in my app so there might be a collision there? It's needed for other routes but should I disable it for routes that use multer? Here is the full issue? https://stackoverflow.com/questions/76064309/unexpected-end-of-form-at-callfinal-error – Dzsonah Apr 24 '23 at 07:58
12

I also got the exact same error.

Before using multer I had installed express-fileupload. When I unistalled it using the command npm uninstall express-fileupload I could get rid of the error.

And if it is the same case with you don't forget to delete the commands you already added for express-fileupload module. (like requiring fileupload)

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Faith Sabu
  • 121
  • 4
5

Hi there I ran into the same issue for me was the lack of a bodyParser middleware that allows our requests files to parsed into Buffers.

I was able to resolve the problem like so in express:

   var bodyParser = require('body-parser')

bodyParser.json([options])
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
  • Thanks for the reply, were those the only two lines you required? What options did you use? – Updog Jun 14 '22 at 08:39
  • I used no options just invoked the function . and yes those were the lines i required , is your issue resolved ? – Orchide Irakoze SR Jun 14 '22 at 16:18
  • sorry, maybe I'm being stupid but it looks like you have passed [options] to the bodyParser.json(). If I try to run the server it crashes because options hasn't been defined. In any case, I looked at the documentation and the default options should be enough, but I am still getting the same error – Updog Jun 15 '22 at 08:25
  • Sorry , i don't receive message notifications . would you mind trying https://github.com/mscdex/connect-busboy instead of multer ? And how are you testing that endPoint ? are you naming the upload field to "upload" . if you're testing with postman you should set "upload" as the field name of your file input . – Orchide Irakoze SR Jun 15 '22 at 20:34
  • I have this on my server.js but I get the same issue. – Dzsonah Apr 24 '23 at 07:59
2

In my case, the cause was other middleware. Check for other middleware running before multer. For me, the issue was express-openapi-validator middleware. Once I removed that middleware, it worked as expected.

Rob
  • 123
  • 1
  • 10
1

Using body-parser package worked for me:

const bodyParser = require('body-parser')
// ...
app.use(bodyParser()) // support encoded bodies

My upload single file route:

const multer = require('multer')
const express = require('express')
const router = express()
const path = require('path') // node built-in path package

// needs "app.use(bodyParser())" middleware to work

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, process.cwd() + '/public/')
    },
    filename: function (req, file, cb) {
        // generate the public name, removing problematic characters
        const originalName = encodeURIComponent(path.parse(file.originalname).name).replace(/[^a-zA-Z0-9]/g, '')
        const timestamp = Date.now()
        const extension = path.extname(file.originalname).toLowerCase()
        cb(null, originalName + '_' + timestamp + extension)
    }
})

const upload = multer({
    storage: storage,
    limits: { fileSize: 1 * 1024 * 1024 }, // 1 Mb
    fileFilter: (req, file, callback) => {
        const acceptableExtensions = ['png', 'jpg', 'jpeg', 'jpg']
        if (!(acceptableExtensions.some(extension => 
            path.extname(file.originalname).toLowerCase() === `.${extension}`)
        )) {
            return callback(new Error(`Extension not allowed, accepted extensions are ${acceptableExtensions.join(',')}`))
        }
        callback(null, true)
    }
})

router.post('/api/upload/single', upload.single('file'), (req, res) => {
    res.status(200).json(req.file)
})

module.exports = {
    uploadRouter: router
}
Rashomon
  • 5,962
  • 4
  • 29
  • 67
1

Try downgrading Multer to 1.4.3. It worked for me.

See https://github.com/expressjs/multer/issues/1144

Lucio Crusca
  • 1,277
  • 3
  • 15
  • 41
0

I think this is may causes by the responsed end,so in your continuous Middleware,you can do upload file at last. i do this resolve problems.

const upload = multer({
  dest: "./uploads",
});
app.use(upload.any());
app.post(
  "/upload",
  (req, res, next) => {
    res.end("文件上传成功");
  },
  upload.single("fileKey")
);
0

try using these it work

const express = require('express')
const app = express()
const path = require('path')
const multer = require('multer')

var filestorageEngine = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null,'./uploads')
    },
    filename:(req,file, cb) => {
        cb(null,"[maues]-" + file.originalname)
    }
})

var upload = multer({
    storage:filestorageEngine
})

app.post('/file', upload.array('file', 3),(req, res) => {
   console.log(req.file)
    res.send("file uploaded successfully")
})

app.listen(5000, ()=> {
    console.log("server running")
})
  • 4
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 25 '22 at 08:31
0

in my frontend or client-side removing the headers in my request. And make sure your inputs are as a formData.

For example:

let formData = new FormData();
formData.append("fileName", file);

const res = await fetch("/api/create-card", {
      method: "POST",
      body: formData,
 })

This worked for me.

0

I think, the problem is in the express and body-parser module, I just eliminated it

app.use(bodyParser.text({ type: '/' }));

and it works!

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
0

In my case I was using the multer middleware twice, that was causing the error. For anyone who can't find a solution check if you made the same mistake.

0

i solved the prob by removing express fileuplod

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 12 '23 at 07:09
0

I had the same issue, however I solved the issue by replacing:

app.use(express.urlencoded(extended:false))

With:

const bodyParser = require("body-parser")

app.use(bodyParser.urlencoded(extended:false))
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
0

In my case replacing the

body: uploadData

to

body: uploadData.getBuffer().toString("utf8")

solved the issue.

Anja
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 24 '23 at 17:09