Search code examples
javascriptnode.jsexpressnodejs-streamcreatewritestream

createWriteStream do not fire an error event when the file is not fully written due to disk space


Here's the problem i'm facing with createWriteStream:

  1. Let's say I have a 100mb file, and i want to write it in another file on the disk
  2. the disk available size is 50mb

my code:

    const fs = require('fs');
    const w = fs.createWriteStream('/path/in/other/partition/destination.txt');
    const r = fs.createReadStream("/source.txt")

    r.on('data', function(chunk) {
    w.write(chunk);
    });

    w.on('close', function () {
       console.log('closed1');
    });
    w.on('error', (e) => console.log('error'));

Now i expect to get an error when there's no more space available, but what I got instead is a partially created file of 50mb size (available disk size before start writing) without any error.

  • Is there any explanation for this behavior ?
  • how can I force createWriteStream to fire an error event in this case knowing that i do not know the file size beforehand?

node version: v18.16.0


Solution

  • First off, disk full is not considered an error in the standard nodejs file write operations. You pass in a number of bytes to write and get back how many bytes were written. If the two values are not the same (all bytes were not written), then one assumes that's probably a disk full issue, but it doesn't trigger an error at the lowest level of writing.

    And, nodejs streams don't seem to check to see if all bytes were written and don't seem to make it easy for the code using a stream to check for that either. This seems like a giant hole in the implementation to me. Streams are wonderful to use when errors don't happen and are sometimes a nightmare when errors do happen because they don't communicate them back cleanly in some cases. I've taken to using them less and less and just do manual reads and writes where I have total control. That might be advised here.

    Looking at the file writeStream code, it does not appear to ever check if all bytes are written and that's the only way to detect a disk becoming full on a write. So, it appears to me that the stream doesn't check for disk full and doesn't make it an error. It's possible there's some other way it might notice, but I'm not seeing it myself in the writeStream code.

    It's also possible that the stream is filling up its buffer and w.write() is returning false and you're not checking for that which would tell you that the stream is backed up. You could then wait for the drain event and set a timer and if you hit the timeout you set, then no drain event is coming and something is definitely wrong, perhaps a disk full.

    And, you could also pass a callback to w.write() and see if you get an error there, but I don't see anywhere for that callback to communicate the error either.