165
votes

I'm working on uploading a file to my app using the multer npm module.

The multer function I have defined is to allow a single file uploaded to the file system. Everything works during run time; the issue is after I upload the file I get an error below. Any advice appreciated on where to look.

Error:

Unexpected field

Error: Unexpected field
    at makeError (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\lib\make-error.js:12:13)
    at wrappedFileFilter (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\index.js:39:19)
    at Busboy.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\lib\make-middleware.js:97:7)
    at Busboy.emit (events.js:118:17)
    at Busboy.emit (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\lib\main.js:31:35)
    at PartStream.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\lib\types\multipart.js:205:13)
    at PartStream.emit (events.js:107:17)
    at HeaderParser.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:51:16)
    at HeaderParser.emit (events.js:107:17)
    at HeaderParser._finish (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\HeaderParser.js:70:8) 

app.js

var multer = require('multer');
var app = express();
var fs = require('fs');

//. . . 

var upload = multer({ dest: 'upload/'});
var type = upload.single('file');

app.post('/upload', type, function (req,res) {
  var tmp_path = req.files.recfile.path;
  var target_path = 'uploads/' + req.files.recfile.name;
fs.readFile(tmp_path, function(err, data)
{
  fs.writeFile(target_path, data, function (err)
  {
    res.render('complete');
  })
});

Index.hbs

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name='recfile' placeholder="Select file"/>
    <br/>
    <button>Upload</button>
</form>

#Package.json
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "easy-zip": "0.0.4",
    "express": "~4.13.1",
    "hbs": "~3.1.0",
    "less-middleware": "1.0.x",
    "morgan": "~1.6.1",
    "multer": "~1.0.0",
    "serve-favicon": "~2.3.0"
  }
}
11

11 Answers

185
votes

We have to make sure the type= file with name attribute should be same as the parameter name passed in upload.single('attr')

var multer  = require('multer');
var upload = multer({ dest: 'upload/'});
var fs = require('fs');

/** Permissible loading a single file, 
    the value of the attribute "name" in the form of "recfile". **/
var type = upload.single('recfile');

app.post('/upload', type, function (req,res) {

  /** When using the "single"
      data come in "req.file" regardless of the attribute "name". **/
  var tmp_path = req.file.path;

  /** The original name of the uploaded file
      stored in the variable "originalname". **/
  var target_path = 'uploads/' + req.file.originalname;

  /** A better way to copy the uploaded file. **/
  var src = fs.createReadStream(tmp_path);
  var dest = fs.createWriteStream(target_path);
  src.pipe(dest);
  src.on('end', function() { res.render('complete'); });
  src.on('error', function(err) { res.render('error'); });

});
242
votes

The <NAME> you use in multer's upload.single(<NAME>) function must be the same as the one you use in <input type="file" name="<NAME>" ...>.

So you need to change

var type = upload.single('file')

to

var type = upload.single('recfile')

in you app.js

Hope this helps.

31
votes

A follow up to vincent's answer.

Not a direct answer to the question since the question is using a form.

For me, it wasn't the name of the input tag that was used, but the name when appending the file to the formData.

front end file

   var formData = new FormData();
   formData.append('<NAME>',this.new_attachments)

web service file:

   app.post('/upload', upload.single('<NAME>'),...
5
votes

This for the Api you could use

 const express        = require('express');
 const bodyParser     = require('body-parser');
 const app = express();
 var multer = require('multer');
 const port = 8000;
 app.use(bodyParser.json());
 app.use(bodyParser.urlencoded({ extended: true }));

 app.listen(port, ()=>{
 console.log('We are live on' + port);
 });

 var upload = multer({dest:'./upload/'});

 app.post('/post', upload.single('file'), function(req, res) {
  console.log(req.file);
 res.send("file saved on server");
 });

This also works fine used on Postman but the file doesn't comes with .jpg extension any Advice? As commented below

This is the default feature of multer if uploads file with no extension, however, provides you the the file object, using which you can update the extension of the file.

var filename = req.file.filename; 
var mimetype = req.file.mimetype; 
mimetype = mimetype.split("/"); 
var filetype = mimetype[1]; 
var old_file = configUploading.settings.rootPathTmp+filename; 
var new_file = configUploading.settings.rootPathTmp+filename+'.'+filetype; 
rname(old_file,new_file);
4
votes

since 2 images are getting uploaded! one with file extension and other file without extension. to delete tmp_path (file without extension)

after
src.pipe(dest);

add below code

fs.unlink(tmp_path); //deleting the tmp_path

2
votes

Unfortunately, the error message doesn't provide clear information about what the real problem is. For that, some debugging is required.

From the stack trace, here's the origin of the error in the multer package:

function wrappedFileFilter (req, file, cb) {
  if ((filesLeft[file.fieldname] || 0) <= 0) {
    return cb(makeError('LIMIT_UNEXPECTED_FILE', file.fieldname))
  }

  filesLeft[file.fieldname] -= 1
  fileFilter(req, file, cb)
}

And the strange (possibly mistaken) translation applied here is the source of the message itself...

'LIMIT_UNEXPECTED_FILE': 'Unexpected field'

filesLeft is an object that contains the name of the field your server is expecting, and file.fieldname contains the name of the field provided by the client. The error is thrown when there is a mismatch between the field name provided by the client and the field name expected by the server.

The solution is to change the name on either the client or the server so that the two agree.

For example, when using fetch on the client...

var theinput = document.getElementById('myfileinput')
var data = new FormData()
data.append('myfile',theinput.files[0])
fetch( "/upload", { method:"POST", body:data } )

And the server would have a route such as the following...

app.post('/upload', multer(multerConfig).single('myfile'),function(req, res){
  res.sendStatus(200)
}

Notice that it is myfile which is the common name (in this example).

2
votes

Different file name which posted as "recfile" at <input type="file" name='recfile' placeholder="Select file"/> and received as "file" at upload.single('file')

Solution : make sure both sent and received file are similar upload.single('recfile')

1
votes

I solve this issues looking for the name that I passed on my request

I was sending on body:

{thumbbail: <myimg>}

and I was expect to:

upload.single('thumbnail')

so, I fix the name that a send on request

0
votes

In my scenario this was happening because I renamed a parameter in swagger.yaml but did not reload the docs page.

Hence I was trying the API with an unexpected input parameter.
Long story short, F5 is my friend.

0
votes

probably you are not giving the same name as you mentioned in the upload.single('file') .

0
votes

In my case, I had 2 forms in differents views and differents router files. The first router used the name field with view one and its file name was "inputGroupFile02". The second view had another name for file input. For some reason Multer not allows you set differents name in different views, so I dicided to use same name for the file input in both views.

enter image description here