I'm learning Fastify so I've written a simple program to upload files using Fastify-Formidable. The file is successfully uploaded and moved to it's destination directory with the help of the mv package. However, as this happens, Fastify throws an Unhandled Promise Error in the console. My code is:
const insertManyWorkers = async (request, reply) => {
try {
await request.parseMultipart();
let oldpath = await request.files.picture.path;
let uploadDir = '/home/hamza/Documents/Web-Projects/Personal/test/img/' + request.files.picture.name;
await mv(oldpath, uploadDir, {
mkdirp: true
}, function(err) {
if (err) {
reply.send(err);
} else {
reply.code(200).send('uploaded')
}
});
} catch (error) {
console.log(error);
reply.send(error)
};
};
The error is as follows:
01:17:24 ✨ incoming request POST xxx /workers/insert 01:17:24 🚨 Promise may not be fulfilled with 'undefined' when statusCode is not 204 FastifyError: Promise may not be fulfilled with 'undefined' when statusCode is not 204 at /home/user-1/Documents/Web-Projects/test/node_modules/fastify/lib/wrapThenable.js:30:30 at processTicksAndRejections (node:internal/process/task_queues:96:5) { "err": { "type": "FastifyError", "message": "Promise may not be fulfilled with 'undefined' when statusCode is not 204", "stack": "FastifyError: Promise may not be fulfilled with 'undefined' when statusCode is not 204\n at /home/hamza/Documents/Web-Projects/Personal/test/node_modules/fastify/lib/wrapThenable.js:30:30\n at processTicksAndRejections (node:internal/process/task_queues:96:5)", "name": "FastifyError", "code": "FST_ERR_PROMISE_NOT_FULFILLED", "statusCode": 500 } } 01:17:24 ✨ request completed 18ms [fastify-cli] process forced end 01:17:30 ✨ Server listening at http://0.0.0.0:5000
Additionally, Fastify also logs [fastify-cli] process forced end after a few milliseconds of the file upload.
It seems the back-end doesn't know when the request ends and therefore forcefully terminates the upload process. Not sure where to go from here so any help would be appreciated.
When using an async route handler (insertManyWorkers
in your case), Fastify expects that the Promise returned by the handler resolves with a defined value (that will be sent as reply body) unless you explicitly set the reply status code to 204, which means "No Content".
One additional problem is that your code is awaiting on mv
which is a callback-based function that doesn't return a promise. In order to invoke mv
with await
inside an async
function, you can use promisify:
const mv = require('mv');
const util = require('util');
const mvPromisified = util.promisify(mv);
Also, unless you are planning to do anything meaningful with the potentially caught error, you can get rid of the try/catch
block so that any errors thrown inside the handler function are caught by Fastify (and possibly logged by Pino depending on your log level setting), which then responds with code 500. Consequently, your insertManyWorkers
function might look like this:
const insertManyWorkers = async (request, reply) => {
await request.parseMultipart();
let oldpath = await request.files.picture.path;
let uploadDir = '/home/hamza/Documents/Web-Projects/Personal/test/img/' + request.files.picture.name;
await mvPromisified(oldpath, uploadDir, {
mkdirp: true
})
return 'uploaded';
};
It is also worth noting that await
in let oldpath = await request.files.picture.path
is unnecessary, as request.files.picture.path
is just a property access and not an invocation of a function returning a promise that could be awaited on.