Open junioroo opened 1 year ago
Same ! I struggled 2 days to make sense of the problem ! The culprit was this package . While uploading a file , if you go and check If the file was uploaded or not ... there is a resulting unhandled promise rejection and the whole server crashes
@junioroo Well , I tried a few more packages to handle async errors , but unfortunately , they too could not catch the async errors thrown by multer . So , well I went ahead and added next
to this particular controller that used multer , and kept the rest of the controllers the same ( no next )
//[+]2. Setting up multer function
const handleMultipartData = multer({
storage,
limits: { fileSize: 1000000 * 5 },
}).single('image'); // 5mb
//[+] Function to create a new product
// eslint-disable-next-line @typescript-eslint/require-await
const create = async (req: Request, res: Response, next: NextFunction) => {
// Multipart form data
// eslint-disable-next-line @typescript-eslint/no-misused-promises
handleMultipartData(req, res, async (err) => {
try {
let product;
if (err)
return next(CustomErrorHandler.multerError('❌ Error at multer start'));
if (!req.file) {
return next(
CustomErrorHandler.multerError(
'❌ File Not Present in Multer Request'
)
);
}
const filePath = req.file.path;
console.log('filePath ', filePath);
//[+]validate the form data for product fileds
//[-] You need to go to the `server.ts` file and apply the middleware to parse multipart form
try {
const body: unknown = await req.body;
console.log('product body', JSON.stringify(body, null, 2));
//[+] Extract product fields from the body and create a Product document
const { name, price, size } = productValidator.parse(body);
console.log(
'🚀 ~ file: productController.ts:56 ~ handleMultipartData ~ const { name, price, size }:',
name,
price,
size
);
product = await Product.create({
name,
price,
size,
image: filePath,
});
//[+]Delete the uploaded file in case of validation error
} catch (err) {
//[+] Return error res in case error
fs.unlink(`${APP_ROOT}/${filePath}`, (err) => {
if (err)
throw CustomErrorHandler.multerError('Could not delete file');
else console.log('✅ Uploaded file deleted');
});
return next(CustomErrorHandler.multerError((err as Error).message));
}
return res.status(201).json(product);
} catch (err) {
next(err);
}
});
This is not just for multer, just tested and its when an inner function throws an unhandled rejection.
app.get('/async', async (req: Request, res: Response) => {
async function test() {
throw new Error('ASYNC test;' + Date.now());
}
test();
});
Crashes the app. Interestingly, adding await
infront of the call to test()
fixes the error. I think something similar is happening here.
I would think the easiest workaround is to not use nesting and use a cleaner syntax anyways (await).
Instead of using the callback, see if you can use await
I've changed one of the tests to match the same approach I'm using in my application but it's not being handled:
When I execute the test, I'm only receiving the crash "error" in the terminal, not the expected status from the handler!
Thanks for the help