You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"WriteStream.close" from "fs" module not executing the callback #2950
The callback passed to WriteStream.close function from the "fs" module is not called in certain situations (see below). The same applies to the ReadStream.
varfs=require('fs');vara=fs.createWriteStream('/tmp/aaa');a.close(console.log.bind(null,'closed'));// prints "closed"a.close(console.log.bind(null,'closed'));// the "close" callback is not executed the second time
varfs=require('fs');vara=fs.createWriteStream('/dev/full');a.on('error',console.log.bind(null,'error'));a.write('a');// prints "error"a.close(console.log.bind(null,'closed'));// the "close" callback is not called after an error
The first example is basically a logic bug because .close() is not an idempotent operation. We could probably do a little better there because node does attempt to close the file descriptor again. That will fail with EBADF most of the time but sometimes, it ends up closing the wrong file descriptor.
Sorry, I tested my original examples in REPL. The snippets below can be executed as scripts.
In Scripts 1, 2 & 3, the file descriptor is already closed, when "close" function is called.
Result: callback is NOT called.
Expected: callback should be called, possibly with error.
In Script 4, the "closed" property is not set and "close" event has not been emitted yet, when "close" function is called.
Result: callback is called and "error" (EBADF) is emitted.
Expected: error should not be emitted.
// prints:// "error { [Error: ENOSPC: no space left on device, write] errno: -28, code: 'ENOSPC', syscall: 'write' }"// "closed1"varfs=require('fs');vara=fs.createWriteStream('/dev/full');a.on('close',function(){console.log('closed1');a.close(console.log.bind(null,'closed2'));});a.on('error',console.log.bind(null,'error'));a.write('a');
varfs=require('fs');vara=fs.createWriteStream('/tmp/aaa');a.close(console.log.bind(null,'closed'));// prints "closed"a.close(console.log.bind(null,'closed'));
closed
closed
events.js:160
throw er; // Unhandled 'error' event
^
Error: EBADF: bad file descriptor, close
at Error (native)
So, if we think this is a needed feature, we should in fact document it, and add an error parameter to that callback. But I'm all in for deprecating close() for fs.createWriteStream(), and removing in two cycles from now.
Activity
bnoordhuis commentedon Sep 18, 2015
The first example is basically a logic bug because
.close()is not an idempotent operation. We could probably do a little better there because node does attempt to close the file descriptor again. That will fail with EBADF most of the time but sometimes, it ends up closing the wrong file descriptor.Your second example works for me with v4.1.0.
bnoordhuis commentedon Sep 18, 2015
#2955
gkubisa commentedon Sep 20, 2015
Sorry, I tested my original examples in REPL. The snippets below can be executed as scripts.
In Scripts 1, 2 & 3, the file descriptor is already closed, when "close" function is called.
Result: callback is NOT called.
Expected: callback should be called, possibly with error.
In Script 4, the "closed" property is not set and "close" event has not been emitted yet, when "close" function is called.
Result: callback is called and "error" (EBADF) is emitted.
Expected: error should not be emitted.
Script 1.
Script 2.
Script 3.
Script 4.
fs: don't fail with EBADF on double close
Trott commentedon May 2, 2016
What is the correct behavior when calling
close(cb)on an already-closed fs stream?close()Asking for a friend.
bnoordhuis commentedon May 6, 2016
@Trott I've been coming around to the idea that an EBADF exception is the most appropriate.
evanlucas commentedon Jan 30, 2017
This is what I'm currently getting on v6.9.4:
Is that intended behavior now?
mcollina commentedon Feb 7, 2017
@evanlucas I think that's not correct and we have a bug, a user should expect to receive that error in the callback, currently it is not.
evanlucas commentedon Feb 7, 2017
wait,
.close(cb)thecbcan have anerrargument? Has that always been the case?mcollina commentedon Feb 7, 2017
@evanlucas The correct way to end a stream is to call
.end(). That deal with all the cases.close()is not part of the Stream API, nor it's document anywhere forfs.https://nodejs.org/api/fs.html#fs_class_fs_writestream.
So, if we think this is a needed feature, we should in fact document it, and add an error parameter to that callback. But I'm all in for deprecating
close()forfs.createWriteStream(), and removing in two cycles from now.However, we still need to document and fix
ReadableStream.closebecause that's what is being used here: https://github.com/nodejs/node/blob/master/lib/fs.js#L2022.If we look at: https://github.com/nodejs/node/blob/master/lib/fs.js#L1857, it's not doing anything.
Ahum.. I'll try to assemble a PR for this anyway.
mcollina commentedon Feb 13, 2017
Fixed in b1fc774.
fs: avoid emitting error EBADF for double close
fs: avoid emitting error EBADF for double close