Multer: Request pending if file limit exceed

Created on 21 Jul 2015  路  19Comments  路  Source: expressjs/multer

I use multer with single file variant.

var multer  = require('multer');

  var avatarMulter = multer({
    dest: './uploads/avatar',
    limits: {
      fieldNameSize: 100,
      fileSize: 1048576,
      files: 1,
      fields: 1
    }
  });

app.post('/api/photo', avatarMulter.single('file'), auth.requiresLogin, usersCustom.processAvatarImage);

Log:

Error: File too large
    at makeError (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\lib\make-error.js:12:13)
    at abortWithCode (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\lib\make-middleware.js:64:22)
    at FileStream.<anonymous> (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\lib\make-middleware.js:116:11)
    at FileStream.emit (events.js:104:17)
    at PartStream.onData (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\lib\types\multipart.js:212:18)
    at PartStream.emit (events.js:107:17)
    at readableAddChunk (_stream_readable.js:163:16)
    at PartStream.Readable.push (_stream_readable.js:126:10)
    at Dicer._oninfo (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:192:36)
    at SBMH.<anonymous> (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:127:10)
    at SBMH.emit (events.js:118:17)
    at SBMH._sbmh_feed (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\node_modules\dicer\node_modules\streamsearch\lib\sbmh.js:188:10)
   at SBMH.push (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\node_modules\dicer\node_modules\streamsearch\lib\sbmh.js:56:14)
    at Dicer._write (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:109:17)
    at doWrite (_stream_writable.js:301:12)
    at writeOrBuffer (_stream_writable.js:288:5)
    at Dicer.Writable.write (_stream_writable.js:217:11)
    at Multipart.write (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\lib\types\multipart.js:282:24)
    at Busboy._write (C:\Users\Viktor\Develop\OnlineKonzultace\sources\onlinekonzultace\node_modules\multer\node_modules\busboy\lib\main.js:72:16)
    at doWrite (_stream_writable.js:301:12)
    at writeOrBuffer (_stream_writable.js:288:5)
    at Busboy.Writable.write (_stream_writable.js:217:11)
POST /api/photo 500 - - 74.112 ms

But express still processing request (rrequest is still pending from browser). Also invalid file is not deleted from /upload/avatar directory.

I try use checking err directly (below), but problem is same. My processing avatar function is never run after mutler CB. I also try remove everything except mutler callback and problem is still in.

multerInstance(req, res, function (err) {
      if (err) {
        console.log(err);
        return res.status(500).json({error: 'error'});
      }
      console.log('OK');
      res.json({});
    })
bug

Most helpful comment

Here is complete code:

var express = require('express')
var multer  = require('multer')
var logger = require('morgan');
var upload = multer(
  { 
    dest: 'uploads/', 
    limits: {
       fields: 1,
       files: 1,
       fileSize: 512000
    }
  })

var app = express();

app.use(express.static('public'));
app.use(logger());

app.post('/avatar', upload.single('file'), function (req, res, next) {  
  res.end('finished');
})

app.use(function(err, req, res, next) {
  console.log('ERROR');
  res.status(500);
  res.end('');
  console.error(err.stack);
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

All 19 comments

I made a most simply example as possible

var express = require('express')
var multer  = require('multer')
var logger = require('morgan');
var upload = multer(
  { 
    dest: 'uploads/', 
    limits: {
       fields: 1,
       files: 1,
       fileSize: 512000
    }
  })

var app = express();

app.use(express.static('public'));
app.use(logger());

app.post('/avatar', upload.single('file'), function (req, res, next) {  
  res.end('finished');
})

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

Pending problem start when i add error handler function to express:

app.use(function(err, req, res, next) {
  console.log('ERROR');
  res.status(500);
  res.end('');
  console.error(err.stack);
});

There is a HTML index.html file:

<html>
  <body>
    <form action="/avatar" method="POST" enctype="multipart/form-data">
      <input type="file" name="file" /> 
      <input type="submit" value="Send" />
    </form>
  </body>
</html>

With file which exceed defined limit, POST request pending and doesn't end. Without error handler function, request ends, with exception stack as response body.

where did you add the error handling function? (it matters)

Here is complete code:

var express = require('express')
var multer  = require('multer')
var logger = require('morgan');
var upload = multer(
  { 
    dest: 'uploads/', 
    limits: {
       fields: 1,
       files: 1,
       fileSize: 512000
    }
  })

var app = express();

app.use(express.static('public'));
app.use(logger());

app.post('/avatar', upload.single('file'), function (req, res, next) {  
  res.end('finished');
})

app.use(function(err, req, res, next) {
  console.log('ERROR');
  res.status(500);
  res.end('');
  console.error(err.stack);
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

Hi @vmartis, sorry for taking my time to respond. I can't seem to reproduce your problem.

Could you please check out the code in #173 and run all the tests? I've left instructions on how to do that there. Thanks :+1:

Hi,

Exact same problem since upgrading to 1.0.1.

The problem occurs when uploading a file which has a size > limits.fileSize.

The error is delegated to express but the response seems to never end.

Here is a simple example:

var express = require('express');
var multer  = require('multer');
var router  = express.Router();

var multerConf = multer({
  dest: './uploads/',
  limits: {
    fileSize: 5 * 1000000
  }
});

router.post('/', multerConf.single('file'), function (req, res) {
  res.status(200).send({file: req.file});
});

router.use(function (err, req, res, next) {
  res.status(413).send('File too large');
})

module.exports = router;

I am doing something wrong?

Also, what's the best way to delete a partially uploaded file (previously it was done via onFileSizeLimit using fs.unlink('./' + file.path))

Partially uploaded files will now be removed automatically :fireworks:

Otherwise I don't think you are doing anything wrong, this seems to be a confirmed bug and I think that I have traced it to somewhere between multer and busboy. For some reason the incoming pipe won't start again after I unpipe it to busboy and try to resume it.

I have similar issue with the following setup:

   var uploader = multer({
        storage: multer.diskStorage({
            destination: uploadDirFn,
            filename: uploadFileNameFn
        }),
        limits: {
            files: 1,
            fileSize: UPLOAD_LIMIT
        }
    });
    var upload = uploader.single('file');

app.post('/api/upload/file', uploadFile); // this is xhr request

function uploadFile(req, res, next) {
  // using multer as suggested here: https://github.com/expressjs/multer#error-handling
  // res is not used, so I don't pass it
  upload(req, null, function (err) {
    if (err) {
        return res.json({error: err.toString()}); // HTTP response is never sent!
    }

    // success
    res.json({result: true});
  });
}

I see this issue constantly: it doesn't matter if this is the very first upload that exceeds the limit or it comes after some successful uploads (when limit is met).

Should be fixed by dfa2095f76966eb7ea2cee6b446f2e7de710fb48, please reopen if issue persists.

Finally :fireworks: :tropical_drink:

I confirm my issue above is fixed. Great work!

Thank you!

Turns out that this issue was probably a bug in Node.js, and I just managed to slightly work around it :sob:

See joyent/node#25823

There is one work around which I have used in my current project

File: make-middleware.js
change "function done(err)" at end of this function

Replace
Line 52: onFinished(req, function () { next(err) })

With:
Line 52: onFinished(req, function () { if( typeof err != "undefined" && err.code == 'LIMIT_FILE_SIZE') { req.fileSizeError = 1; next() } else next(err) })

And in app file you can change the code to

app.post('/upload', upload.single('upload'), function (req, res, next) {
    if(typeof req.fileSizeError != "undefined") {
        res.send({"error":"File too large"});// to display filesize error
    } else {
        res.send({"file":req.file}); // when file uploaded successfully
    }
}); 

I am also getting the same error.
Using express : 4.13.4
Multer : current version 1.1.0

used @sumedhm-iprogrammer hack currently to work. But hoping this will get fixed soon

Which version of Node.js are you using?

Hey @LinusU
I am using 5.6.0, I hope the issue is to do with the node.js version.
Thanks

If you are getting error

Error: File too large
at makeError (/home/amar/xvb/node_modules/multer/lib/make-error.js:12:13)
at abortWithCode (/home/amar/xvb/node_modules/multer/lib/make-middleware.js:77:22)
at FileStream. (/home/amar/xvb/node_modules/multer/lib/make-middleware.js:139:11)
at emitNone (events.js:67:13)
at FileStream.emit (events.js:166:7)
at PartStream.onData (/home/amar/xvb/node_modules/busboy/lib/types/multipart.js:220:18)
at emitOne (events.js:77:13)
at PartStream.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:153:18)
at PartStream.Readable.push (_stream_readable.js:111:10)
at Dicer._oninfo (/home/amar/xvb/node_modules/dicer/lib/Dicer.js:191:36)
at SBMH. (/home/amar/xvb/node_modules/dicer/lib/Dicer.js:127:10)
at emitMany (events.js:108:13)
at SBMH.emit (events.js:182:7)
at SBMH._sbmh_feed (/home/amar/xvb/node_modules/streamsearch/lib/sbmh.js:188:10)
at SBMH.push (/home/amar/xvb/node_modules/streamsearch/lib/sbmh.js:56:14)
at Dicer._write (/home/amar/xvb/node_modules/dicer/lib/Dicer.js:109:17)
at doWrite (_stream_writable.js:300:12)
at writeOrBuffer (_stream_writable.js:286:5)
at Dicer.Writable.write (_stream_writable.js:214:11)
at Multipart.write (/home/amar/xvb/node_modules/busboy/lib/types/multipart.js:290:24)
at Busboy._write (/home/amar/xvb/node_modules/busboy/lib/main.js:74:16)

File: make-middleware.js
change "function done(err)" at end of this function

Replace
Line 52: onFinished(req, function () { next(err) })

With:
Line 52: onFinished(req, function () { if( typeof err != "undefined" && err.code == 'LIMIT_FILE_SIZE') { req.fileSizeError = 1; next() } else next(err) })

And in app file you can change the code to

app.post('/upload', upload.single('upload'), function (req, res, next) {
if(typeof req.fileSizeError != "undefined") {
res.send({"error":"File too large"});// to display filesize error
} else {
res.send({"file":req.file}); // when file uploaded successfully
}
});

I found most appropriate way to fix above issue

var storage = multer.diskStorage({
destination: function (req, file, callback) {
var avatarMimeType = ['image/png','image/jpg','image/jpeg'];
if(file.fieldname === 'avatar' && avatarMimeType.indexOf(file.mimetype) >= 0){
callback(null, './uploads/users/profile/images/');
}else{
callback(null, './uploads');
}
},
filename: function (req, file, callback) {
callback(null, req.authUser._id + path.extname(file.originalname);
}
});

var upload = multer({ storage: storage, limits:{ fileSize: 1048576 } });

// To upload user profile images 
var userProfileImageUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]);

api.post('/users/profile' ,function ( req, res, next) {
userProfileImageUpload(req, res, function (err) {
if (err) {
res.status(413).send({"error":err});
}else{
res.status(200).send({"file":req.files});
}
});
});

Their is no need to chnage middleare [ multer ] file
File: make-middleware.js
change "function done(err)" at end of this function

Replace
Line 52: onFinished(req, function () { next(err) })

With:
Line 52: onFinished(req, function () { if( typeof err != "undefined" && err.code == 'LIMIT_FILE_SIZE') { req.fileSizeError = 1; next() } else next(err) })

I can confirm the above works, it worked for me, it will work for other broken limits encountered by multer as well

Is there any possibility to make it work without having to modify the lib?

Was this page helpful?
0 / 5 - 0 ratings