Error handling when uploading file using multer with expressjs
Asked Answered
C

11

20

I am using multer to save the file on server developed through express & nodejs.

I am usign following code.

var express = require('express'),
    multer  = require('multer')

var app = express()

app.get('/', function(req, res){
  res.send('hello world');
});

app.post('/upload',[ multer({ dest: './uploads/'}), function(req, res){

    res.status(204).end()
}]);

app.listen(3000);

Multer saves the file for me in the specified destination folder.

All this is working fine but I have following questions:

  1. If the file saving fails for various reasons, it looks like my route will always return status 204.
  2. I am not sure if status 204 is retured after file is saved or while the file is getting saved asynchronously, status 204 is returned.
Carma answered 15/6, 2015 at 6:49 Comment(1)
For 2022 it's important to note that if there's an error multer simply passes along to your normal Express error route. If for some reason you need to handle it separately, see Arya's code.Brooksbrookshire
M
16

You can handle errors using the onError option:

app.post('/upload',[
  multer({
    dest    : './uploads/',
    onError : function(err, next) {
      console.log('error', err);
      next(err);
    }
  }),
  function(req, res) {
    res.status(204).end();
  }
]);

If you call next(err), your route handler (generating the 204) will be skipped and the error will be handled by Express.

I think (not 100% sure as it depends on how multer is implemented) that your route handler will be called when the file is saved. You can use onFileUploadComplete to log a message when the upload is done, and compare that to when your route handler is called.

Looking at the code, multer calls the next middleware/route handler when the file has been uploaded completely.

Moldy answered 15/6, 2015 at 7:11 Comment(6)
onError was removed in Multer 1.0.0.Enticement
I've found an working code with new multer version: github.com/expressjs/multer/issues/336#issuecomment-242906859Rawalpindi
what is the replacement of onError ?Joyous
@HosMercury github.com/expressjs/multer#error-handlingMoldy
How to handle if multer upload is successful and route handler fails?Hallagan
@Hallagan that would depend on how the route handler is implemented, and what exactly you mean by handling it.Moldy
A
30

This is how to write multer middleware that handle upload and errors

const multer = require("multer");

function uploadFile(req, res, next) {
    const upload = multer().single('yourFileNameHere');

    upload(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            // A Multer error occurred when uploading.
        } else if (err) {
            // An unknown error occurred when uploading.
        }
        // Everything went fine. 
        next()
    })
}
Aerospace answered 22/10, 2019 at 0:41 Comment(2)
Note that if you write a response then you should not call next(), if I understand correctly.Camper
accepted answer doesn't works anymore, this one should be the accepted one.Lakendra
M
16

You can handle errors using the onError option:

app.post('/upload',[
  multer({
    dest    : './uploads/',
    onError : function(err, next) {
      console.log('error', err);
      next(err);
    }
  }),
  function(req, res) {
    res.status(204).end();
  }
]);

If you call next(err), your route handler (generating the 204) will be skipped and the error will be handled by Express.

I think (not 100% sure as it depends on how multer is implemented) that your route handler will be called when the file is saved. You can use onFileUploadComplete to log a message when the upload is done, and compare that to when your route handler is called.

Looking at the code, multer calls the next middleware/route handler when the file has been uploaded completely.

Moldy answered 15/6, 2015 at 7:11 Comment(6)
onError was removed in Multer 1.0.0.Enticement
I've found an working code with new multer version: github.com/expressjs/multer/issues/336#issuecomment-242906859Rawalpindi
what is the replacement of onError ?Joyous
@HosMercury github.com/expressjs/multer#error-handlingMoldy
How to handle if multer upload is successful and route handler fails?Hallagan
@Hallagan that would depend on how the route handler is implemented, and what exactly you mean by handling it.Moldy
J
8

Try this

var upload = multer().single('avatar')

app.post('/profile', function (req, res) {
  upload(req, res, function (err) {
    if (err) {
      // An error occurred when uploading 
      return
    }

    // Everything went fine 
  })
}

ref :

http://wiki.workassis.com/nodejs-express-get-post-multipart-request-handling-example/

https://www.npmjs.com/package/multer#error-handling

Jasper answered 19/8, 2016 at 9:34 Comment(0)
A
2

According to the multer documentation (https://github.com/expressjs/multer#error-handling)

Error handling

When encountering an error, Multer will delegate the error to Express. You can display a nice error page using the standard express way.

If you want to catch errors specifically from Multer, you can call the middleware function by yourself. Also, if you want to catch only the Multer errors, you can use the MulterError class that is attached to the multer object itself (e.g. err instanceof multer.MulterError).

code sample

   const multer = require('multer')
   const upload = multer().single('avatar')
   
   app.post('/profile', function (req, res) {
     upload(req, res, function (err) {
       if (err instanceof multer.MulterError) {
         // A Multer error occurred when uploading.
       } else if (err) {
         // An unknown error occurred when uploading.
       }
   
       // Everything went fine.
     })
   })

When we re-write the code in this question with latest version of multer (v1.4.5-lts.1)

const express = require('express');

const multer = require('multer');

const app = express();

const upload = multer({ dest: './uploads/' }).single('fieldName');

app.get('/', (req, res) => {
    res.send('hello world');
});

app.post(
    '/upload',
    (req, res, next) => {
        upload(req, res, (err) => {
            if (err instanceof multer.MulterError) {
                res.status(404).send(err + 'Upload failed due to multer error');
            } else if (err) {
                res.status(404).send(err + 'Upload failed due to unknown error');
            }
            // Everything went fine.
            next();
        });
    },
    (req, res) => {
        res.status(204).end();
    }
);

app.listen(3000);

To check the Multer errors and non multer errors we can add validations using fileFilter and limits eg: I am adding a CSV file filter method and some limits

// CSV file filter - will only accept files with .csv extension
const csvFilter = (req, file, cb) => {
    console.log('csv filter working');
    if (file.mimetype.includes('csv')) {
        cb(null, true);
    } else {
        cb('Please upload only csv file.', false);
    }
};

// adding the csv file checking, file number limit to 1 and file size limit 10 1kb
const upload = multer({
    dest: './uploads/',
    fileFilter: csvFilter,
    limits: { files: 1, fileSize: 1024 } 
}).single('fieldName');

We can see different errors are thrown when we try to upload non CSV file or >1kb sized file or multiple files.

Aeciospore answered 27/9, 2022 at 17:56 Comment(0)
E
2

Since Multer is designed for express to use as middleware, by default call next(err) which falls into nearest error handler middleware

var express = require('express'),
  multer = require('multer')

var app = express()

app.get('/', function (req, res) {
  res.send('hello world');
});

app.post('/upload', multer({ dest: './uploads/' }),

  function (req, res, next) {
    // your logic goes here

    res.status(204).end()
  },
  function (err, req, res, next) {
    // handle your error here
    // if (err instanceof multer.MulterError) {
    //   // handle file size error
    //   if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).send({ error: err.message });
    //   // handle unexpected file error
    //   if (err.code === 'LIMIT_UNEXPECTED_FILE') return res.status(400).send({ error: err.message });
    //   // handle unexpected field key error
    //   if (err.code === 'LIMIT_FIELD_KEY') return res.status(400).send({ error: err.message });
    // }

    res.status(400).end()
  },);

app.listen(3000);
Extemporary answered 22/12, 2023 at 7:35 Comment(0)
G
1

As you can see from the code below (the source from the muter index.js file), if you not pass the onError callback the error will be handled by express.

    fileStream.on('error', function(error) {
      // trigger "file error" event
      if (options.onError) { options.onError(error, next); }
      else next(error);
    });
Ginter answered 20/11, 2015 at 18:53 Comment(0)
H
1

Be careful with the system when the user sends anything to you

I usually set more [*option1]:

process.on('uncaughtException', function(ls){
  // console.log(ls);
  (function(){})();
});

And then:

var upload= multer({ dest: __dirname + '/../uploads/' }).single('photos');
// middle ..
upload(req, res, function (err) {
  if (err instanceof multer.MulterError) {
    // A Multer error occurred when uploading.
    console.log('MulterError', err);
  } else if (err) {
    // An unknown error occurred when uploading.
    // Work best when have [*option1]
    console.log('UnhandledError', err);
  }
  if(err) {
    return res.sendStatus(403);
  }
  res.sendStatus(200);
});

package: "multer": "^1.4.2"

Hearne answered 15/8, 2020 at 1:43 Comment(0)
H
1
    var multer = require('multer')
    var upload = multer().single('avatar')
     
    app.post('/profile', function (req, res) {
      upload(req, res, function (err) {
        if (err instanceof multer.MulterError) {
          handle error
        } else if (err) {
          handle error
        }
        else{
          write you code
        }
      })
    })

you can see this from the documentation

Hendecasyllable answered 13/2, 2021 at 3:36 Comment(0)
S
1

I think the best way is handling error with middleware.

const multerErrorHandling = (err, req, res, next) => {
if (err instanceof multer.MulterError) {
  res.status(400).send("Multer error: " + err.message);
} else {
  next();
}
};
  // you should use after multer to send another respond.
  app.post("/upload", singleUpload,multerErrorHandling,(req, res) => {
Steele answered 27/6, 2023 at 17:18 Comment(0)
P
0

I know its late but it might help others.

Here is how I handle errors and use it safely in my express/typescript project.

const upload = (fieldName: string) => {
  return (req: Request, res: Response, next: NextFunction) => {
    return multer({
      storage: multer.diskStorage({
        destination: (req, file, cb) => {
          if (file.fieldname === 'post') {
            return cb(null, `${path.join(path.dirname(__dirname), 'uploads/postImg')}`);
          } else if (file.fieldname === 'profile') {
            return cb(null, `${path.join(path.dirname(__dirname), 'uploads/ProfilePic')}`);
          } else {
            return cb(new Error(`${file.fieldname} is incorrect`), null);
          }
        },
        filename: (req, file, cb) => {
          return cb(null, `${file.originalname}-${Date.now()}-${file.fieldname}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        const fileExtension = file.mimetype.split('/')[1];
        if (!(fileExtension in allowedFiles)) return cb(null, false);
        return cb(null, true);
      },
      dest: `${path.join(path.dirname(__dirname), 'uploads')}`,
      limits: {
        fileSize: 1024 * 1024 * 3, // 3MB
        files: 1,
      },
    }).single(fieldName)(req, res, (err: any) => {
      if (err instanceof multer.MulterError) {
        // handle file size error
        if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).send({ error: err.message });
        // handle unexpected file error
        if (err.code === 'LIMIT_UNEXPECTED_FILE') return res.status(400).send({ error: err.message });
        // handle unexpected field key error
        if (err.code === 'LIMIT_FIELD_KEY') return res.status(400).send({ error: err.message });
      }
      next();
    });
  };
};




app.post("/upload", (req: Request, res:Response)=>{
res.json({message:"file uploaded"})
})
Pacorro answered 18/1, 2023 at 16:39 Comment(0)
M
0

To bring in notice, that middleware is called when the exact route is hit. Keeping this in mind, we don't want the multer to be called directly, rather we want to create another middleware that should call multer instead.

Firstly, when uploadMiddleware is being called, the upload.single() function gets invoked and returns another function with parameters req, res and a callback function. The callback function has a parameter error (if error is occurred), so, if the error has a value a undefined, congratulations, no error has occurred. And the next() function of uploadMiddleware is called and further code is executed.

Follow code and its explanation Above:

const storage = multer.diskStorage({
    destination: function(req , file , cb){
        cb(null , 'uploads/')
    },
    filename: function (req , file ,cb){
        cb(null,`${Date.now()}${file.originalname}`)
    },
})
const upload = multer({ storage })

function uploadMiddleware(req, res, next) {
    try {
        upload.single('photos')(req, res, function(err) {
            if(err) res.status(400).json({status: 'error', message: err.message})
            else next()
        })
    } catch (error) {
        console.log('errorrororororororoor');
    }
}

app.post('/file', uploadMiddleware, (req, res) => {
    res.end();
})
Metic answered 22/3, 2024 at 7:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.