-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
maxByteLength Error Handling #2
Comments
Hey @jcapcik! Thank you for a very well-written issue :) I'm looking into it right now. Could you please provide a snippet of the code that throws an error, and ideally a minimum reproduction of your issue? That'd greatly help. |
Sure! I'll work on a simple working example to duplicate the issue. |
Thank you! I knew someone will eventually stumble upon an error case like this – handling errors inside streams is a huge PITA. |
@jcapcik nevermind, no need for a snippet. I found a cause, will fix in the nearest time. Turns out, the error was thrown only inside the You can either:
for await (const { filename: originalFilename, byteLength, stream, ...file } of files) {
const newFilename = `${Math.round(Math.random() * 1000)}-${originalFilename}`;
const dest = path.join(os.tmpdir(), newFilename);
stream.pipe(fs.createWriteStream(dest));
/*
`byteSize` resolves only after the entire `file.stream` has been consumed
You should `await byteSize` only AFTER the code that consumes the stream
(e.g. uploading to AWS S3, loading into memory, etc.)
*/
const length = await byteLength;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// You can either wrap this into a try-catch block, or
// wrap the outer for-await-of loop into try-catch.
results.push({ ...file, dest, originalFilename, newFilename, length});
}
|
So here's my working example, but please let me know if I missed something. I created a file
Ran Then I created a
And this is the error before the server crashes:
|
Whoops @rafasofizada, well I included it anyway :-) Oh shoot! I apologize! I've been thinking about this wrong. Here I've been "await"ing whatever is writing to a stream (either writing to a file in my example, or uploading to S3). But what I didn't realize is that So yeah, changing my example to this, it works great!
|
Dang. Okay, so it doesn't crash Node at least, but I still have the issue where it will still write the file because the transform stream completes, it just has truncated the file. So this gets back to where I would need to catch the error and remove the file, instead of the stream itself erroring. It seems like error handling is supported in stream implementation - https://nodejs.org/api/stream.html#transform_transformchunk-encoding-callback
At least in the Writeable stream, it's noted that the only reliable way of handling errors is to pass it to the callback:
If course you have far more experience with this than I do, so maybe there are still gotchas to calling the callback with an error. |
You're right. I'll have to change the way errors are handled inside This is really a design problem – I explicitly don't throw any erros inside the stream implementation, but rather propogate it up (using I'll fix this ASAP and add as many test cases as I can think of. Thanks a lot for spotting this and researching it thoroughly! One thing I wanted to ask – how did you discover this library? E.g. what search terms, from which website, etc. I'll be working on actively promoting this library, and knowing how people stumble upon it is very useful to me right now :) |
Awesome! Hopefully the way I was intending to use it matches how others would want to use it, so hopefully this will be a beneficial change. I ultimately stumbled upon your Reddit post 😄 I'm not sure exactly how I found it, but I was too many hours into researching how best to handle file uploads in Node, more specifically on utilizing streams with async code and limiting file sizes, and getting frustrated in the process. I just thought that this had to have been figured out many times over already. Ultimately, I could have just gotten by with an existing package that utilizes temporary files, but the idea of having access to the fields right away without having to process the files, and to iterate through each file without having to read it in/store it, and to stream the file data out somewhere without having to worry about cleanup, and just simply do async things easily within the I really appreciate your responsiveness on this! For now, I'm just going to not implement a file size limit, and revisit it whenever you make some changes - so don't rush on my part! If anything else comes up while using the package in production I'll let you know. |
1. `byteLength` event is not necessary when you have standard 'finish'/'end'/'close'/'error' events + bytes/truncated getters 2. Pre-setting event handlers (especially on 'error') and wrapping them into a Promise proved to cause lots of peculiar bugs and race conditions.
Hey @jcapcik. Firstly, thanks again for using Pechkin and submitting this bug report. It made me look deep into the codebase and learn lots of stuff about the library that I didn't even know myself :) The issue is fixed. I've added an edited version of your bug reproduction to the tests, you can find it in The actual fix is pretty small, I simply needed to One should instead wait until the stream finishes processing, listen to Version 2.0.0 (removing Let me know what you think! |
@rafasofizada, my sincere apologies that I did not respond sooner. I finally got around to upgrading to v2 to support better error handling when the file size limit is reached, and it worked perfect! Thanks again for your work on this! |
First off, thank you @rafasofizada for writing pechkin! I was initially using formidable to handle file uploads, but was growing frustrated with async handling and wasn't able to stream data from the request without using a temporary file. Also note that I'm new to Node, and came from PHP, so I'm mostly fumbling my way around.
My goal with using pechkin was as follows:
multipart/form-data
request.@aws-sdk/lib-storage
.maxFileByteLength
, abort the S3 upload.The problem I'm running into is with using
abortOnFileByteLengthLimit: true
. If the file limit is reached, the S3 upload will fail (instead of just being truncated but successfully sent), but the error thrown fromFileIterator
is not caught and seemingly cannot be caught, so my node process crashes:Ideally, at least to a layman such as myself, it would be preferable for the Transform stream to throw an error when the size limit is reached. Just as a test I tried this, within the
_transform
function withinByteLengthTruncateStream
, and it seemed to function as expected. I'm able to catch the error and continue to iterate through the files.By looking at the examples and the tests, it just seems that throwing an error to abort a stream was not a priority. As it stands, it seems the only way I can use this package with a file size limit is to set
abortOnFileByteLengthLimit: false
, checkbyteLength
after the S3 upload completes, and iftruncated: true
, then manually delete the file that was just uploaded. I'll also probably require aContent-Length
header and validate the size ahead of time, although that only protects when the request comes from our app - it seems a separate request can be made with a fake content length, and there's no built-in validation in Node for multipart requests.If you have any thoughts or suggestions, I'm all ears!
The text was updated successfully, but these errors were encountered: