expressjs / multer

Node.js middleware for handling `multipart/form-data`.
MIT License
11.55k stars 1.05k forks source link

MulterError class doesn't allow custom messages. #659

Open JemiloII opened 5 years ago

JemiloII commented 5 years ago

https://github.com/expressjs/multer/blob/a04f29376aba2ecf7062ff6a00749a4afb39db78/lib/multer-error.js#L16

I didn't expect this behavior. I expected it to create a custom message that I provided. File type not supported! I am checking meme types using the filter. I thought I could use the MulterError class to nicely catch and organize its errors.

LinusU commented 5 years ago

MulterError was only intended to be created from inside of Multer and handed out from the library.

What is your use case? Could you not simply do new Error('File type not supported')?

JemiloII commented 5 years ago

Well yes, but it would have been nice to use the MutlerError for processing the filleFilter or have the cb error param pass the message to the MulterError

LinusU commented 5 years ago

but it would have been nice to use the MutlerError for processing the filleFilter

Would you mind elaborating a bit? What is that would nice? or why/how would it be nice?

JemiloII commented 5 years ago

So in the multer config

We can do this:

const upload = Multer({
    dest: '...'
    limits: { ... }.
    fileFilter(req, file, callback) { ... }
})

For limits, any limits check that fails will throw a multer error. For fileFilter, inorder for it to fail, we either add an error to the callback function or return false. I see false good for multiple files uploads that we do not want to stop all the uploads. So where does this error end up going when using express? Well to the last middleware express designates for error handling.

app.use((error, req, res, next)) {
    // error will not be a Multer error.
    if (error instanceof MulterError) {
        res.status(400).send({error: 'File not supported!'});
    } else {
        res.sendStatus(500);
    }
});

When we try and use the Multer error handler, it doesn't use the provided error because

this.message = errorMessages[code]

I handle my server errors in this fashion and for my own custom errors I create, I would add a status property and other properties so that i can do something like this:

if (error instanceof MyError) {
    res.status(error.status).send({error: error.message, file: error.originalname});
}
anuraghazra commented 4 years ago

I could not find a good solution to this. and all of the issues related to this are also seems like outdated. Although @JemiloII 's solution works.

Improving on Jemilo's solution we can also throw multer.MulterError instead of creating custom MyError instance

const fileFilter = (req, file, cb) => {
  if (
    file.mimetype === "image/png" ||
    file.mimetype === "image/jpg" ||
    file.mimetype === "image/jpeg"
  ) {
    cb(null, true);
  } else {
    // if validation failed then generate error
    cb(new multer.MulterError("LIMIT_UNEXPECTED_FILE", file), false);
  }
};
const upload = multer({ storage, fileFilter });
app.use(function (err, req, res, next) {
  if (err instanceof multer.MulterError) {
    // fileUpload.js
    console.log(err.field)
    res.status(500).send({ error: "Invalid File format. must be PNG,JPG,JPEG" })
  } else next();
});

Referencing https://github.com/expressjs/multer/blob/master/lib/multer-error.js

HarshithaKP commented 4 years ago

@anuraghazra I tried your solution, it doesn't look like working. The only way to handle errors is as documented here : https://github.com/expressjs/multer#error-handling

halain commented 4 years ago

@anuraghazra solution work form mi,

ImageFilter function

const imageFilter = (req: Request , file: Express.Multer.File, cb: Function) => {
    if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
         cb( new multer.MulterError("LIMIT_UNEXPECTED_FILE") , false);
    }else {
        cb(null, true);
    } 
}

Express handlerError

server.app.use((err:Error, req: Request, res: Response, next: NextFunction) => {
    console.error(err.stack);

    //Catch multer error
    if (err instanceof multer.MulterError) {
        let message: string = '';
        if (err.code === 'LIMIT_FILE_SIZE'){ message='Archivo excede el tamaño permitido' };
        if (err.code === 'LIMIT_FILE_COUNT'){ message='No debe exceder el numero máximo de archivos' };
        if (err.code === 'LIMIT_UNEXPECTED_FILE'){ message='Tipo de archivo no permitido' };
        return res.status(400).json({
            ok: false,
            message: message.length ? message : err.message
        })
    }

    res.status(500).send('Server error!');
});

Sorry for my english

Saifullah-dev commented 2 weeks ago

Improving on @anuraghazra 's solution, we can use err.code for error message:

if (fs.existsSync(fullFilePath)) {
  return cb(new multer.MulterError("File already exists!", file), false);
}
// Error handling middleware
app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    return res.status(400).json({ error: err.code });
  }

  res.status(500).json({ error: err.message });
});

Response:

{
  "error": "File already exists!"
}