fastify-multipart: Request hangs if an error is thrown while processing a file

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.24.3

Plugin version

8.0.0

Node.js version

18.x

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

20.04

Description

The for..await of promise doesn’t get fulfilled (or rejected) if an error is throw when processing a single file. For example, in the following code, the line “done processing all files” doesn’t get logged.

const files = await request.files();

for await (const { file, filename } of files) {
  console.log("start processing file", filename);

  try {
    const storage = new Writable({
      write(chunk, encoding, callback) {
        // trigger error:
        callback(new Error("write error"));
      },
    });

    await pipeline(file, storage);
  } catch (error) {
    console.log("caught error while processing file", filename, error);
    // note that the error isn't rethrown here, so this error is now handled
    // and processing should proceed
  }

  console.log("done processing file", filename);
}

console.log("done processing all files");

return reply.send(files);

Also, if the try..catch is removed, everything freezes after “start processing file”.

On a separate/related note, is it possible to use @fastify/multipart but with the stream-based api instead of the generators?

Steps to Reproduce

Repro: https://github.com/joelmukuthu/fastify-multipart-hanging-bug.

Expected Behavior

That the request would not hang. If the error is not handled properly (e.g. if there’s no try..catch in the example above), I’d expect that the request fails with an error.

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 18 (14 by maintainers)

Most upvoted comments

Thanks for the description

We’re currently rewriting inner components of multipart so my focus is mostly there right now 😃

Will investigate though

I have a partial solution to this but I currently don’t fully understand why it’s partial — it doesn’t work if the try catch isn’t there

Respectfully, the architecture of the whole plugin (after including busboy) is a little messy and hard to keep track of for me

That’s why I’m interested in a simpler rewrite but I wanted to start with busboy first

Anyway I can put the PR up tonight maybe others can figure out why it doesn’t work without the try catch