Unexpected end of form error when using Multer
Asked Answered
I

18

29

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.

Illsorted answered 8/6, 2022 at 10:50 Comment(6)
whats @Illsorted (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.Deonnadeonne
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.Illsorted
Hi , are you able to find the solution? I am stuck in the issue for sometime.Cestode
@Cestode 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 :DIllsorted
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.Interrogation
@HeikoTheißen Hi, no it is not related to my problem but I appreciate it anyway. I would not have noticed that. Thanks!Illsorted
G
18

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

Gutshall answered 3/8, 2022 at 9:40 Comment(2)
This was my issue too, Thanks!Woolworth
Thanks for pointing this out, this was also my issue. I had forgotten that I had previously installed and used express-fileupload.Contributory
A
16

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
  }
}
Ashtray answered 7/10, 2022 at 18:19 Comment(3)
For Next.js, This is the right answer.Chak
For others, to be clear, this export is in the API route file. nextjs.org/docs/api-routes/request-helpers Should mark as correct answer.Delaney
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? #76064809Identification
L
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])
Leucippus answered 13/6, 2022 at 12:1 Comment(5)
Thanks for the reply, were those the only two lines you required? What options did you use?Illsorted
I used no options just invoked the function . and yes those were the lines i required , is your issue resolved ?Leucippus
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 errorIllsorted
Sorry , i don't receive message notifications . would you mind trying 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 .Leucippus
I have this on my server.js but I get the same issue.Identification
L
3

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.

Lafave answered 4/9, 2022 at 14:3 Comment(1)
Thanks, I had the same issue! Amazing, just a few days apart lol.Insobriety
C
3

i solved the prob by removing express fileuplod

Checani answered 11/6, 2023 at 18:20 Comment(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.Furore
P
2

Try downgrading Multer to 1.4.3. It worked for me.

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

Pastrami answered 16/1, 2023 at 14:26 Comment(1)
This is not a solution anymore unfortunately: [email protected] because Multer 1.x is affected by CVE-2022-24434.Begat
P
2

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))
Ptero answered 12/7, 2023 at 10:7 Comment(1)
app.use(bodyParser.urlencoded({extended:false})); //You forgot the { }Mesial
T
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
}
Tengler answered 19/8, 2022 at 9:31 Comment(1)
deprecated (2024)Mesial
B
1

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.

Bethea answered 29/10, 2022 at 18:52 Comment(0)
I
1

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.

Iyar answered 23/4, 2023 at 9:6 Comment(1)
Was the case for me too!Battaglia
R
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")
);
Riordan answered 16/7, 2022 at 13:58 Comment(0)
F
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!

Fenestra answered 7/12, 2022 at 5:56 Comment(0)
B
0

In my case replacing the

body: uploadData

to

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

solved the issue.

Bakeman answered 24/8, 2023 at 15:26 Comment(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.Furore
T
0

I had this problem when I moved the backend from monolithic to microservices because I had to use a proxy. I was using proxy('users:90') from the require('express-http-proxy') library and it constantly gave me exactly this error. I was only able to get it working with the createProxyMiddleware(...) , from the require('http-proxy-middleware') library.

In the gateway microservice, I directed the routes as follows:

const proxy =  require('express-http-proxy');
app.use("/users",  proxy('users:80')); 

The problem was that this function didn't fill in the headers properly. Since in this microservice I had to upload files and also common routes with JSON output, I created the following middleware function:

app.use('/users', createProxyMiddleware({ // this is necessary for handle fileUpload
      target: `http://users:80`,
      changeOrigin: true,
      pathRewrite: {
        '^/users': '',
      },
      onProxyReq: (proxyReq: any, req: any, res: any) => {
        const contentType = req.headers['content-type']; // get content type of request
        if (req.body && typeof contentType !== 'undefined' && !contentType.includes('multipart/form-data')) {  // verify if isn't Post with upload files
          const bodyData = JSON.stringify(req.body);
          proxyReq.setHeader('Content-Type', 'application/json');
          proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
          proxyReq.write(bodyData);
        }
      },
      onError: (err: any, req: any, res: any) => {
        console.error('Proxy error:', err);
        res.status(500).send('Proxy error');
      },
    }));

The onProxyReq function was necessary specify because after these change, fileupload works and the normal api routes don't. After adding this middleware, works normally.

Trimolecular answered 19/12, 2023 at 15:41 Comment(0)
B
0

For me, it was because I wrote upload.any() in the routes file router.put('/update', upload.any(), updateUser);

removing upload.any() fixed the error for me.

Birck answered 26/5 at 5:40 Comment(0)
F
0

If you are using many libraries for handling form data and request body data then remove code for that and only use these below lines

app.use(express.json({ limit: '150mb' }));
app.use(express.urlencoded({
  extended: true
}));

See the Picture here screenshot

Friend answered 18/6 at 13:16 Comment(0)
H
0

Not to install the latest version. Be sure to install [email protected]. It works well.

Hern answered 2/7 at 11:41 Comment(0)
H
-1

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")
})
Haroldson answered 23/7, 2022 at 2:34 Comment(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.Furore

© 2022 - 2024 — McMap. All rights reserved.