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
Darwin ... 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:33:47 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T6030 arm64
Linux ... 6.8.0-39-generic #39-Ubuntu SMP PREEMPT_DYNAMIC Sat Jul 6 02:50:39 UTC 2024 aarch64 GNU/Linux
Subsystem
readline
What steps will reproduce the bug?
The following code creates a dummy fs that throws an error on the fs.close() call.
This error can be caught with events.once() when using the fs directly.
When using the fs together with readline, the error is not caught by events.once().
import{once}from'events'import{createReadStream}from'fs'import{createInterface}from'readline'letposition=0constmyDummyFilesystem={read: (fd,buffer,offset,len,pos,cb)=>{buffer.write("A\n");cb(null,((position+=2)<=10) ? 2 : 0,buffer)},close: (x,cb)=>{cb(newError("close failed"))},open: (name,flags,mode,cb)=>{cb(undefined,42)}}asyncfunctionbad(){constfile=createReadStream('app.js',{fs: myDummyFilesystem})constrl=createInterface({input: file})letlineNr=0rl.on('line',(line)=>console.log(`bad ${++lineNr}${line}`))awaitonce(rl,'close')// DOES NOT CATCH Error of the fs.close() CALL}asyncfunctiongood(){constfile=createReadStream('app.js',{fs: myDummyFilesystem})letlineNr=0file.on('data',(line)=>console.log(`good ..`))awaitonce(file,'close')// CATCHES Error of the fs.close() CALL}await(good().catch(e=>console.error("nice first catch",e)))position=0bad().catch(e=>console.error("nice second catch",e))
How often does it reproduce? Is there a required condition?
always
What is the expected behavior? Why is that the expected behavior?
the await once(...) also catches the error on fs.close()
It'd be useful that you paste a error stack trace.
You haven't answered the "Why is that the expected behavior?" question, IMO if the read stream fails to close is different from the readline failing to close, you should listed to the 'error' and/or 'close' even of the read stream.
Hi, this is not a bug per-se; you should be listening to the stream errors, not the readline errors. The readline is not failing, it is your stream.
import{once}from'events'import{createReadStream}from'fs'import{createInterface}from'readline'letposition=0constmyDummyFilesystem={read: (fd,buffer,offset,len,pos,cb)=>{buffer.write("A\n");cb(null,((position+=2)<=10) ? 2 : 0,buffer)},close: (x,cb)=>{cb(newError("close failed"))},open: (name,flags,mode,cb)=>{cb(undefined,42)}}asyncfunctionbad(){constfile=createReadStream('app.js',{fs: myDummyFilesystem})constrl=createInterface({input: file})letlineNr=0rl.on('line',(line)=>console.log(`bad ${++lineNr}${line}`))awaitonce(file,'close')// NOW DOES CATCH Error of the fs.close() CALL}asyncfunctiongood(){constfile=createReadStream('app.js',{fs: myDummyFilesystem})letlineNr=0file.on('data',(line)=>console.log(`good ..`))awaitonce(file,'close')// CATCHES Error of the fs.close() CALL}await(good().catch(e=>console.error("nice first catch",e)))position=0bad().catch(e=>console.error("nice second catch",e))
You could consider that snippet as a solution for this. But this may raise some discussion around what events we listen to from the backing stream in readline.
If i fail in the the fs.read() call instead of the fs.close() call, the error is caught by the readline interface with await once(rl, 'close') .
I would expect that i either need to handle all input stream errors on my own, or that the readline interface provides an wrapper that abstracts/forwards all errors of the input stream.
Output with read errors:
node nodeError2.js
nice first catch v23.11.0 Error: read failed
at file:///Users/js/readline/nodeError2.js:8:17
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:98:5)
.
.
.
.
.
node:events:485
throw er; // Unhandled 'error' event
^
Error: close failed
at file:///Users/js/readline/nodeError2.js:27:14
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
Emitted 'error' event on ReadStream instance at:
at emitErrorNT (node:internal/streams/destroy:170:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
new Code with read error:
import{once}from'events'import{createReadStream}from'fs'import{createInterface}from'readline'letreadError=newError("read failed")letcloseError=nullletposition=0constmyDummyFilesystem={read: (fd,buffer,offset,len,pos,cb)=>{buffer.write("A\n");cb(readError,((position+=2)<=10) ? 2 : 0,buffer)},close: (x,cb)=>{cb(closeError)},open: (name,flags,mode,cb)=>{cb(undefined,42)}}asyncfunctionfun(){constfile=createReadStream('app.js',{fs: myDummyFilesystem})constrl=createInterface({input: file})letlineNr=0rl.on('line',(line)=>console.log(`.`))awaitonce(rl,'close')// DOES NOT CATCH Error of the fs.close() CALL}awaitfun().catch(e=>console.error("nice first catch",process.version,e))readError=nullcloseError=newError("close failed")position=0awaitfun().catch(e=>console.error("nice second catch",process.version,e))
Activity
aduh95 commentedon May 12, 2025
It'd be useful that you paste a error stack trace.
You haven't answered the "Why is that the expected behavior?" question, IMO if the read stream fails to close is different from the readline failing to close, you should listed to the
'error'and/or'close'even of the read stream.juanarbol commentedon May 12, 2025
Hi, this is not a bug per-se; you should be listening to the stream errors, not the readline errors. The readline is not failing, it is your stream.
You could consider that snippet as a solution for this. But this may raise some discussion around what events we listen to from the backing stream in readline.
cc // @nodejs/streams
BenderMarkusKremer commentedon May 12, 2025
If i fail in the the fs.read() call instead of the fs.close() call, the error is caught by the readline interface with
await once(rl, 'close').I would expect that i either need to handle all input stream errors on my own, or that the readline interface provides an wrapper that abstracts/forwards all errors of the input stream.
Output with read errors:
new Code with read error:
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor
doc: document error event on readline InterfaceConstructor